markdown docs added

pull/6212/head
Nikita Koksharov 4 months ago
parent b70035df24
commit 2047a4f913

@ -0,0 +1,92 @@
# Redisson - Easy Redis Java client<br/>and Real-Time Data Platform
High-performance async and lock-free Java client for Redis and Valkey based on [Netty](http://netty.io) framework.
## Features
* Thread-safe implementation
* JDK 1.8+ up to the latest version compatible
* Android compatible
* [Redis](https://redis.io) compatible - from 3.0 up to the latest version
* [Valkey](https://valkey.io) compatible - from 7.2.5 up to the latest version
* Supported deployment types
* [Proxy](configuration.md/#proxy-mode)
* [Multi-Cluster](configuration.md/#multi-cluster-mode)
* [Multi-Sentinel](configuration.md/#multi-sentinel-mode)
* [Single](configuration.md/#single-mode)
* [Cluster](configuration.md/#cluster-mode)
* [Sentinel](configuration.md/#sentinel-mode)
* [Replicated](configuration.md/#replicated-mode)
* [Master and Slaves](configuration.md/#master-slave-mode)
* Amazon Web Services compatible
* [AWS Elasticache Serverless](https://aws.amazon.com/elasticache/features/#Serverless)
* [AWS Redis Global Datastore](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/Redis-Global-Datastore.html)
* [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html)
* [Amazon MemoryDB](https://aws.amazon.com/memorydb)
* Microsoft Azure compatible
* [Azure Redis Cache](https://azure.microsoft.com/en-us/services/cache/)
* [Azure Redis Cache active-passive replication](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-geo-replication)
* [Azure Redis Cache active-active replication](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-active-geo-replication)
* Google Cloud Memorystore compatible
* [Google Cloud Redis](https://cloud.google.com/memorystore/docs/redis/)
* [Google Cloud Redis High availability](https://cloud.google.com/memorystore/docs/redis/high-availability)
* Redis Enterprise compatible
* [Redis Enterprise](https://redis.com/redis-enterprise/)
* [Redis Enterprise Active-Active databases](https://docs.redis.com/latest/rs/databases/active-active/get-started/)
* [Redis Enterprise Multiple Active Proxy](https://docs.redis.com/latest/rs/databases/configure/proxy-policy/#about-multiple-active-proxy-support)
* IBM Cloud compatible
* [IBM Cloud Databases for Redis](https://www.ibm.com/cloud/databases-for-redis)
* Aiven compatible
* [Aiven for Redis](https://aiven.io/redis)
* Supports auto-reconnection
* Supports failed to send command auto-retry
* Supports OSGi
* Supports SSL
* Asynchronous connection pool
* Lua scripting
* [RediSearch](data-and-services/services.md/#redisearch-service)
* [JSON datatype](data-and-services/objects.md/#json-object-holder)
* [JSON Store](data-and-services/collections.md/#json-store)
* [Reactive Streams](api-models.md/#reactive-api) API
* [RxJava3](api-models.md/#rxjava-api) API
* [Asynchronous](api-models.md/#synchronous-and-asynchronous-api) API
* Local cache support including [Caffeine](https://github.com/ben-manes/caffeine)-based implementation
* [Cache API implementations](cache-api-implementations.md)
Spring Cache, JCache API (JSR-107), Hibernate Cache, MyBatis Cache, Quarkus Cache, Micronaut Cache
* [Distributed Java objects](data-and-services/objects.md)
Object holder, JSON holder, Binary stream holder, Geospatial holder, BitSet, PublishSubscribe, Bloom filter, HyperLogLog
* [Distributed Java counters](data-and-services/counters.md)
AtomicLong, AtomicDouble, LongAdder, DoubleAdder
* [Distributed Java collections](data-and-services/collections.md)
JSON Store, Map, Multimap, Set, List, SortedSet, ScoredSortedSet, LexSortedSet, Queue, Deque, Blocking Queue, Bounded Blocking Queue, Blocking Deque, Delayed Queue, Priority Queue, Priority Deque
* [Distributed Java locks and synchronizers](data-and-services/locks-and-synchronizers.md)
Lock, FairLock, MultiLock, RedLock, ReadWriteLock, Semaphore, PermitExpirableSemaphore, CountDownLatch
* [Distributed services](data-and-services/services.md)
Remote service, Live Object service, Executor service, Scheduler service, MapReduce service
* [Microservices integration](microservices-integration.md)
Helidon, Micronaut, Quarkus
* [Integration with Spring framework](integration-with-spring.md)
Spring Boot Starter, Spring Cache, Spring Session, Spring Transaction Manager, Spring Cloud Stream, Spring Data Redis
* [Web Session Management](web-session-management.md)
Apache Tomcat Session, Spring Session, Micronaut Session
* [Transactions API](transactions.md)
* [Redis pipelining](pipelining.md) (command batches)
* Supports many popular codecs ([Kryo](https://github.com/EsotericSoftware/kryo), [Jackson JSON](https://github.com/FasterXML/jackson), [Avro](http://avro.apache.org/), [Smile](http://wiki.fasterxml.com/SmileFormatSpec), [CBOR](http://cbor.io/), [MsgPack](http://msgpack.org/), [Amazon Ion](https://amzn.github.io/ion-docs/), [LZ4](https://github.com/jpountz/lz4-java), [Snappy](https://github.com/xerial/snappy-java), [Protobuf](https://github.com/protocolbuffers/protobuf) and JDK Serialization)
* 2000+ unit tests
## Comparing solutions
- [Redisson vs Jedis](https://redisson.org/feature-comparison-redisson-vs-jedis.html)
- [Redisson vs Lettuce](https://redisson.org/feature-comparison-redisson-vs-lettuce.html)
- [Redis vs Apache Ignite](https://redisson.org/feature-comparison-redis-vs-ignite.html)
- [Redis vs Hazelcast](https://redisson.org/feature-comparison-redis-vs-hazelcast.html)
- [Redis vs Ehcache](https://redisson.org/feature-comparison-redis-vs-ehcache.html)
## Success stories
- [Moving from Hazelcast to Redis / Datorama](https://engineering.datorama.com/moving-from-hazelcast-to-redis-b90a0769d1cb)
- [Migrating from Hazelcast to Redis / Halodoc](https://blogs.halodoc.io/why-and-how-we-move-from-hazelcast-to-redis-2/)
- [Distributed Locking with Redis (Migration from Hazelcast) / ContaAzul](https://carlosbecker.com/posts/distributed-locks-redis/)
- [Migrating from Coherence to Redis](https://www.youtube.com/watch?v=JF5R2ucKTEg)
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.

@ -0,0 +1,121 @@
### Synchronous and Asynchronous API
Redisson instances are fully thread-safe.
Synchronous and Asynchronous API could be reached via [RedissonClient](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RedissonClient.html) interface.
Most Redisson objects extend asynchronous interface with asynchronous methods which mirrors synchronous methods. Like below:
```java
// RAtomicLong extends RAtomicLongAsync
RAtomicLong obj = client.getAtomicLong("myLong");
obj.compareAndSet(1, 401);
RAtomicLongAsync objAsync = client.getAtomicLong("myLong");
RFuture<Boolean> future = objAsync.compareAndSetAsync(1, 401);
```
Asynchronous methods return [RFuture](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RFuture.html) object which extends [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html) interface.
```java
future.whenComplete((res, exception) -> {
// handle both result and exception
});
// or
future.thenAccept(res -> {
// handle result
}).exceptionally(exception -> {
// handle exception
});
```
Avoid to use blocking methods in future listeners. Listeners executed by netty-threads and delays in listeners may cause errors in Redis or Valkey request/response processing. Use follow methods to execute blocking methods in listeners:
```java
future.whenCompleteAsync((res, exception) -> {
// handle both result and exception
}, executor);
// or
future.thenAcceptAsync(res -> {
// handle result
}, executor).exceptionallyAsync(exception -> {
// handle exception
}, executor);
```
### Reactive API
Reactive API could be reached via [RedissonReactiveClient](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RedissonReactiveClient.html) interface.
Redisson's implementation based on [Project Reactor](https://projectreactor.io).
Usage example:
```java
RedissonReactiveClient client = redissonClient.reactive();
RAtomicLongReactive atomicLong = client.getAtomicLong("myLong");
Mono<Boolean> cs = longObject.compareAndSet(10, 91);
Mono<Long> get = longObject.get();
get.doOnSuccess(res -> {
// ...
}).subscribe();
```
### RxJava API
RxJava API could be reached via [RedissonRxClient](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RedissonRxClient.html) interface.
Redisson's implementation based on [RxJava3](https://github.com/ReactiveX/RxJava).
Usage example:
```java
RedissonRxClient client = redissonClient.rxJava();
RAtomicLongRx atomicLong = client.getAtomicLong("myLong");
Single<Boolean> cs = longObject.compareAndSet(10, 91);
Single<Long> get = longObject.get();
get.doOnSuccess(res -> {
// ...
}).subscribe();
```
### Retry policy
Redisson implements auto-retry policy per operation. Retry policy is controlled by [retryAttempts](configuration.md) and [retryInterval](configuration.md) settings. These settings are applied to each Redisson object. [timeout](configuration.md) setting is applied when the Redis or Valkey command was successfully sent.
Settings above can be overridden per Redisson object instance. These settings apply to each method of a given Redisson object instance.
Here is an example with `RBucket` object:
```java
RedissonClient client = Redisson.create(config);
RBucket<MyObject> bucket = client.getBucket('myObject');
// sync way
bucket.get();
// async way
RFuture<MyObject> result = bucket.getAsync();
// instance with overridden retryInterval and timeout parameters
RBucket<MyObject> bucket = client.getBucket(PlainOptions.name('myObject')
.timeout(Duration.ofSeconds(3))
.retryInterval(Duration.ofSeconds(5)));
```

File diff suppressed because it is too large Load Diff

@ -0,0 +1,492 @@
## Micronaut Cache
### Eviction, local cache and data partitioning
Redisson provides various Micronaut Cache implementations with multiple important features:
**local cache** - so called `near cache` used to speed up read operations and avoid network roundtrips. It caches Map entries on Redisson side and executes read operations up to **45x faster** in comparison with common implementation. Local cache instances with the same name connected to the same pub/sub channel. This channel is used for exchanging of update/invalidate events between all instances. Local cache store doesn't use `hashCode()`/`equals()` methods of key object, instead it uses hash of serialized state.
**data partitioning** - although any Cache object is cluster compatible its content isn't scaled/partitioned across multiple Redis or Valkey master nodes in cluster. Data partitioning allows to scale available memory, read/write operations and entry eviction process for individual Map instance in cluster.
**1. Scripted eviction**
Allows to define `time to live` or `max idle time` parameters per map entry. Eviction is done on Redisson side through a custom scheduled task which removes expired entries using Lua script. Eviction task is started once per unique object name at the moment of getting Map instance. If instance isn't used and has expired entries it should be get again to start the eviction process. This leads to extra Redis or Valkey calls and eviction task per unique map object name.
Entries are cleaned time to time by `org.redisson.eviction.EvictionScheduler`. By default, it removes 100 expired entries at a time. This can be changed through [cleanUpKeysAmount](../configuration.md) setting. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 5 second to 30 minutes by default. This time interval can be changed through [minCleanUpDelay](../configuration.md) and [maxCleanUpDelay](../configuration.md). For example, if clean task deletes 100 entries each time it will be executed every 5 seconds (minimum execution delay). But if current expired entries amount is lower than previous one then execution delay will be increased by 1.5 times and decreased otherwise.
Available implementations:
|Setting prefix | Local cache | Data<br/>partitioning | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :----------:| :----------:|
|redisson.caches.*<br/><sub><i>open-source version</i></sub> | ❌ | ❌ | ❌ |
|redisson.caches.*<br/><sub><i>[Redisson PRO](http://redisson.pro) version</i></sub> | ❌ | ❌ | ✔️ |
|redisson.local-caches.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ✔️ | ❌ | ✔️ |
|redisson.clustered-caches.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ❌ | ✔️ | ✔️ |
|redisson.clustered-local-caches.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ✔️ | ✔️ | ✔️ |
**2. Advanced eviction**
Allows to define `time to live` parameter per map entry. Doesn't use an entry eviction task, entries are cleaned on Redis or Valkey side.
Available implementations:
|Setting prefix | Local cache | Data<br/>partitioning | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :----------:| :----------:|
|redisson.caches-v2.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ❌ | ✔️ | ✔️ |
|redisson.local-caches-v2.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ✔️ | ✔️ | ✔️ |
**3. Native eviction**
Allows to define `time to live` parameter per map entry. Doesn't use an entry eviction task, entries are cleaned on Redis side.
Requires **Redis 7.4+**.
Available implementations:
|Setting prefix | Local cache | Data<br/>partitioning | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :----------:| :----------:|
|redisson.caches-native.*<br/><sub><i>open-source version</i></sub> | ❌ | ❌ | ❌ |
|redisson.caches-native.*<br/><sub><i>[Redisson PRO](http://redisson.pro) version</i></sub> | ❌ | ❌ | ✔️ |
|redisson.local-caches-native.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ✔️ | ❌ | ✔️ |
|redisson.clustered-caches-native.*<br/><sub><i>available only in [Redisson PRO](http://redisson.pro)</i></sub> | ❌ | ✔️ | ✔️ |
### Usage
**1. Add `redisson-micronaut` dependency into your project**
Maven
```xml
<dependency>
<groupId>org.redisson</groupId>
<!-- for Micronaut v2.0.x - v2.5.x -->
<artifactId>redisson-micronaut-20</artifactId>
<!-- for Micronaut v3.x.x -->
<artifactId>redisson-micronaut-30</artifactId>
<!-- for Micronaut v4.x.x -->
<artifactId>redisson-micronaut-40</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle
```groovy
// for Micronaut v2.0.x - v2.5.x
compile 'org.redisson:redisson-micronaut-20:xVERSIONx'
// for Micronaut v3.x.x
compile 'org.redisson:redisson-micronaut-30:xVERSIONx'
// for Micronaut v4.x.x
compile 'org.redisson:redisson-micronaut-40:xVERSIONx'
```
**2. Add settings into application.yml file**
Config structure is a Redisson YAML configuration -
([single mode](../configuration.md/#single-settings),
[replicated mode](../configuration.md/#replicated-settings),
[cluster mode](../configuration.md/#cluster-settings),
[sentinel mode](../configuration.md/#sentinel-settings),
[proxy mode](../configuration.md/#proxy-mode-settings),
[multi cluster mode](../configuration.md/#multi-cluster-settings),
[multi sentinel mode](../configuration.md/#multi-sentinel-settings))
NOTE: Setting names in camel case should be joined with hyphens (-).
Config example:
```yaml
redisson:
single-server-config:
address: "redis://127.0.0.1:6379"
threads: 16
netty-threads: 32
caches:
my-cache1:
expire-after-write: 10s
expire-after-access: 3s
max-size: 1000
codec: org.redisson.codec.Kryo5Codec
my-cache2:
expire-after-write: 200s
expire-after-access: 30s
```
??? note "Map Cache settings. Click to expand"
**Setting name**: `redisson.caches.[CACHE_NAME].max-size`
Type: `java.lang.Integer`
Description: Max size of this cache. Superfluous elements are evicted using LRU algorithm. If `0` the cache is unbounded.
Default value: `0`
**Setting name**: `redisson.caches.[CACHE_NAME].codec`
Type: `java.lang.Class`
Description: Data codec applied to cache entries.
Default value: `org.redisson.codec.Kryo5Codec`
**Setting name**: `redisson.caches.[CACHE_NAME].expire-after-write`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each write operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.caches.[CACHE_NAME].expire-after-access`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each read operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.caches.[CACHE_NAME].write-behind-batch-size`
Type: `java.lang.Integer`
Description: Write behind tasks batch size. During `MapWriter` methods execution all updates accumulated into a batch of specified size.
Default value: `50`
**Setting name**: `redisson.caches.[CACHE_NAME].write-behind-delay`
Type: `java.time.Duration`
Description: Write behind tasks execution delay. All updates would be applied with lag not more than specified delay.
Default value: `1000ms`
**Setting name**: `redisson.caches.[CACHE_NAME].writer`
Type: `java.lang.Class`
Description: `MapWriter` object used for write-through operations
Default value: `null`
**Setting name**: `redisson.caches.[CACHE_NAME].write-mode`
Type: `java.lang.String`
Description: Write mode. Default is `WRITE_THROUGH`
Default value: `null`
**Setting name**: `redisson.caches.[CACHE_NAME].loader`
Type: `java.lang.Class`
Description: `MapLoader` object used to load entries during read-operations execution
Default value: `null`
```yaml
redisson:
single-server-config:
address: "redis://127.0.0.1:6379"
clustered-caches:
my-cache1:
expire-after-write: 10s
expire-after-access: 3s
max-size: 1000
codec: org.redisson.codec.Kryo5Codec
my-cache2:
expire-after-write: 200s
expire-after-access: 30s
```
??? note "Clustered Map Cache settings. Click to expand"
_These settings are available only in [Redisson PRO](https://redisson.pro)_
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].max-size`
Type: `java.lang.Integer`
Description: Max size of this cache. Superfluous elements are evicted using LRU algorithm. If <code>0</code> the cache is unbounded.
Default value: `0`
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].codec`
Type: `java.lang.Class`
Description: Data codec applied to cache entries.
Default value: `Kryo5Codec`
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].expire-after-write`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each write operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].expire-after-access`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each read operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].write-behind-batch-size`
Type: `java.lang.Integer`
Description: Write behind tasks batch size. During `MapWriter` methods execution all updates accumulated into a batch of specified size.
Default value: `50`
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].write-behind-delay`
Type: `java.time.Duration`
Description: Write behind tasks execution delay. All updates would be applied with lag not more than specified delay.
Default value: `1000ms`
**Setting name**: `redisson.clustered-caches.[CACHE_NAME].writer`
Type: `java.lang.Class`
Description: `MapWriter` object used for write-through operations
Default value: `null`
**Setting name** `redisson.clustered-caches.[CACHE_NAME].write-mode`
Type: `java.lang.String`
Description: Write mode. Default is `WRITE_THROUGH`
Default value: `null`
**Setting name** `redisson.clustered-caches.[CACHE_NAME].loader`
Type: `java.lang.Class`
Description: `MapLoader` object used to load entries during read-operations execution
Default value: `null`
```yaml
redisson:
single-server-config:
address: "redis://127.0.0.1:6379"
clustered-local-caches:
my-cache1:
expire-after-write: 10s
expire-after-access: 3s
max-size: 1000
codec: org.redisson.codec.Kryo5Codec
store-сache-miss: true
eviction-policy: `LFU`
cache-size: 5000
time-to-live: 2s
max-idle: 1s
my-cache2:
expire-after-write: 200s
expire-after-access: 30s
time-to-live: 10s
max-idle: 5s
```
??? note "Clustered Local Map Cache settings. Click to expand"
_These settings are available only in [Redisson PRO](https://redisson.pro)_
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].max-size`
Type: `java.lang.Integer`
Description: Max size of this cache. Superfluous elements are evicted using LRU algorithm. If <code>0</code> the cache is unbounded.
Default value: `0` |
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].codec`
Type: `java.lang.Class`
Description: Data codec applied to cache entries.
Default value: `Kryo5Codec`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].expire-after-write`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each write operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].expire-after-access`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each read operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].write-behind-batch-size`
Type: `java.lang.Integer`
Description: Write behind tasks batch size. During `MapWriter` methods execution all updates accumulated into a batch of specified size.
Default value: `50`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].write-behind-delay`
Type: `java.time.Duration`
Description: Write behind tasks execution delay. All updates would be applied with lag not more than specified delay.
Default value: `1000ms`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].writer`
Type: `java.lang.Class`
Description: `MapWriter` object used for write-through operations
Default value: `null`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].write-mode`
Type: `java.lang.String`
Description: Write mode. Default is `WRITE_THROUGH`
Default value: `null`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].loader`
Type: `java.lang.Class`
Description: `MapLoader` object used to load entries during read-operations execution
Default value: `null`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].cache-size`
Type: `java.lang.Integer`
Description: Local cache size. If size is <code>0</code> then local cache is unbounded.
Default value: `0`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].reconnection-strategy`
Type: `java.lang.String`
Description: Used to load missed updates during any connection failures to Redis. Since, local cache updates can't be executed in absence of connection to Redis:
* `CLEAR` - Clear local cache if map instance has been disconnected for a while.
* `LOAD` - Store invalidated entry hash in invalidation log for 10 minutes. Cache keys for stored invalidated entry hashes will be removed if LocalCachedMap instance has been disconnected less than 10 minutes or whole cache will be cleaned otherwise.
* `NONE` - No reconnection handling
Default value: `NONE`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].sync-strategy`
Type: `java.lang.String`
Description: Used to synchronize local cache changes.
* `INVALIDATE` - Invalidate cache entry across all LocalCachedMap instances on map entry change.
* `UPDATE` - Insert/update cache entry across all LocalCachedMap instances on map entry change.
* `NONE` - No synchronizations on map changes.
Default value: `NONE`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].eviction-policy`
Type: `java.lang.String`
Description: Defines local cache eviction policy.
* `LRU` - uses local cache with LRU (least recently used) eviction policy.
* `LFU` - uses local cache with LFU (least frequently used) eviction policy.
* `SOFT` - uses local cache with soft references. The garbage collector will evict items from the local cache when the JVM is running out of memory.
* `WEAK` - uses local cache with weak references. The garbage collector will evict items from the local cache when it became weakly reachable.
* `NONE` - doesn't use eviction policy, but timeToLive and maxIdleTime params are still working.
Default value: `NONE`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].time-to-live`
Type: `java.lang.Integer`
Description: Time to live duration of each map entry in local cache. If value equals to <code>0</code> then timeout is not applied.
Default value: `0`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].max-idle`
Type: `java.lang.Integer`
Description: Defines max idle time duration of each map entry in local cache. If value equals to <code>0</code> then timeout is not applied.
Default value: `0`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].cache-provider`
Type: `java.lang.String`
Description: Defines Cache provider used as local cache store.
* `REDISSON` - uses Redisson own implementation.
* `CAFFEINE` - uses Caffeine implementation.
Default value: `REDISSON`
**Setting name**: `redisson.clustered-local-caches.[CACHE_NAME].store-сache-miss`
Type: `java.lang.Boolean`
Description: Defines whether to store a cache miss into the local cache.
Default value: `false`
```yaml
redisson:
single-server-config:
address: "redis://127.0.0.1:6379"
local-caches:
my-cache1:
expire-after-write: 10s
expire-after-access: 3s
max-size: 1000
codec: org.redisson.codec.Kryo5Codec
store-сache-miss: true
eviction-policy: `LFU`
cache-size: 5000
time-to-live: 1s
max-idle: 1s
my-cache2:
expire-after-write: 200s
expire-after-access: 30s
eviction-policy: `LFU`
cache-size: 5000
time-to-live: 10s
max-idle: 5s
```
??? note "Local Cached Map Cache settings. Click to expand"
_These settings are available only in [Redisson PRO](https://redisson.pro)_
**Setting name**: `redisson.local-caches.[CACHE_NAME].max-size`
Type: `java.lang.Integer`
Description: Max size of this cache. Superfluous elements are evicted using LRU algorithm. If <code>0</code> the cache is unbounded.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].codec`
Type: `java.lang.Class`
Description: Data codec applied to cache entries.
Default value: `Kryo5Codec`
**Setting name**: `redisson.local-caches.[CACHE_NAME].expire-after-write`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each write operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].expire-after-access`
Type: `java.time.Duration`
Description: Cache entry time to live duration applied after each read operation. Disabled if value is <code>0</code>.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].write-behind-batch-size`
Type: `java.lang.Integer`
Description: Write behind tasks batch size. During `MapWriter` methods execution all updates accumulated into a batch of specified size.
Default value: `50`
**Setting name**: `redisson.local-caches.[CACHE_NAME].write-behind-delay`
Type: `java.time.Duration`
Description: Write behind tasks execution delay. All updates would be applied with lag not more than specified delay.
Default value: `1000ms`
**Setting name**: `redisson.local-caches.[CACHE_NAME].writer`
Type: `java.lang.Class`
Description: `MapWriter` object used for write-through operations
Default value: `null`
**Setting name**: `redisson.local-caches.[CACHE_NAME].write-mode`
Type: `java.lang.String`
Description: Write mode. Default is `WRITE_THROUGH`
Default value: `null`
**Setting name**: `redisson.local-caches.[CACHE_NAME].loader`
Type: `java.lang.Class`
Description: `MapLoader` object used to load entries during read-operations execution
Default value: `null`
**Setting name**: `redisson.local-caches.[CACHE_NAME].cache-size`
Type: `java.lang.Integer`
Description: Local cache size. If size is <code>0</code> then local cache is unbounded.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].reconnection-strategy`
Type: `java.lang.String`
Description: Used to load missed updates during any connection failures to Redis. Since, local cache updates can't be executed in absence of connection to Redis. <br/>`CLEAR` - Clear local cache if map instance has been disconnected for a while. <br/>`LOAD` - Store invalidated entry hash in invalidation log for 10 minutes.<br/>Cache keys for stored invalidated entry hashes will be removed if LocalCachedMap instance has been disconnected less than 10 minutes or whole cache will be cleaned otherwise. <br/>`NONE` - No reconnection handling
Default value: `NONE`
**Setting name**: `redisson.local-caches.[CACHE_NAME].sync-strategy`
Type: `java.lang.String`
Description: Used to synchronize local cache changes. <br/>`INVALIDATE` - Invalidate cache entry across all LocalCachedMap instances on map entry change. <br/>`UPDATE` - Insert/update cache entry across all LocalCachedMap instances on map entry change. <br/>`NONE` - No synchronizations on map changes.
Default value: `NONE`
**Setting name**: `redisson.local-caches.[CACHE_NAME].eviction-policy`
Type: `java.lang.String`
Description: Defines local cache eviction policy. <br/>`LRU` - uses local cache with LRU (least recently used) eviction policy. <br/>`LFU` - uses local cache with LFU (least frequently used) eviction policy. <br/>`SOFT` - uses local cache with soft references. The garbage collector will evict items from the local cache when the JVM is running out of memory. <br/>`WEAK` - uses local cache with weak references. The garbage collector will evict items from the local cache when it became weakly reachable. <br/>`NONE` - doesn't use eviction policy, but timeToLive and maxIdleTime params are still working.
Default value: `NONE`
**Setting name**: `redisson.local-caches.[CACHE_NAME].time-to-live`
Type: `java.time.Duration`
Description: Time to live duration of each map entry in local cache. If value equals to <code>0</code> then timeout is not applied.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].max-idle`
Type: `java.time.Duration`
Description: Defines max idle time duration of each map entry in local cache. If value equals to <code>0</code> then timeout is not applied.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].cache-provider`
Type: `java.lang.String`
Description: Defines Cache provider used as local cache store.<br/>`REDISSON` - uses Redisson own implementation.<br/>`CAFFEINE` - uses Caffeine implementation.
Default value: `0`
**Setting name**: `redisson.local-caches.[CACHE_NAME].store-сache-miss`
Type: `java.lang.Boolean`
Description: Defines whether to store a cache miss into the local cache.
Default value: `false`
Code example:
```java
@Singleton
@CacheConfig("my-cache1")
public class CarsService {
@Cacheable
public List<String> listAll() {
// ...
}
@CachePut(parameters = {"type"})
public List<String> addCar(String type, String description) {
// ...
}
@CacheInvalidate(parameters = {"type"})
public void removeCar(String type, String description) {
// ...
}
}
```

@ -0,0 +1,250 @@
## Spring Cache
Redisson provides various Spring Cache implementations. Each Cache instance has two important parameters: `ttl` and `maxIdleTime`. Data is stored infinitely if these settings are not defined or equal to `0`.
Config example:
```java
@Configuration
@ComponentScan
@EnableCaching
public static class Application {
@Bean(destroyMethod="shutdown")
RedissonClient redisson() throws IOException {
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://127.0.0.1:7004", "redis://127.0.0.1:7001");
return Redisson.create(config);
}
@Bean
CacheManager cacheManager(RedissonClient redissonClient) {
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
// create "testMap" cache with ttl = 24 minutes and maxIdleTime = 12 minutes
config.put("testMap", new CacheConfig(24*60*1000, 12*60*1000));
return new RedissonSpringCacheManager(redissonClient, config);
}
}
```
Cache configuration can be read from YAML configuration files:
```java
@Configuration
@ComponentScan
@EnableCaching
public static class Application {
@Bean(destroyMethod="shutdown")
RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.create(config);
}
@Bean
CacheManager cacheManager(RedissonClient redissonClient) throws IOException {
return new RedissonSpringCacheManager(redissonClient, "classpath:/cache-config.yaml");
}
}
```
### Eviction, local cache and data partitioning
Redisson provides various Spring Cache managers with two important features:
**local cache** - so called `near cache` used to speed up read operations and avoid network roundtrips. It caches Map entries on Redisson side and executes read operations up to **45x faster** in comparison with common implementation. Local cache instances with the same name connected to the same pub/sub channel. This channel is used for exchanging of update/invalidate events between all instances. Local cache store doesn't use `hashCode()`/`equals()` methods of key object, instead it uses hash of serialized state.
**data partitioning** - although Map object is cluster compatible its content isn't scaled/partitioned across multiple Redis or Valkey master nodes in cluster. Data partitioning allows to scale available memory, read/write operations and entry eviction process for individual Map instance in cluster.
**Scripted eviction**
Allows to define `time to live` or `max idle time` parameters per map entry. Eviction is done on Redisson side through a custom scheduled task which removes expired entries using Lua script. Eviction task is started once per unique object name at the moment of getting Map instance. If instance isn't used and has expired entries it should be get again to start the eviction process. This leads to extra Redis or Valkey calls and eviction task per unique map object name.
Entries are cleaned time to time by `org.redisson.eviction.EvictionScheduler`. By default, it removes 100 expired entries at a time. This can be changed through [cleanUpKeysAmount](../configuration.md) setting. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 5 second to 30 minutes by default. This time interval can be changed through [minCleanUpDelay](../configuration.md) and [maxCleanUpDelay](../configuration.md). For example, if clean task deletes 100 entries each time it will be executed every 5 seconds (minimum execution delay). But if current expired entries amount is lower than previous one then execution delay will be increased by 1.5 times and decreased otherwise.
Available implementations:
|Class name | Local<br/>cache | Data<br/>partitioning | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :----------:| :----------:|
|RedissonSpringCacheManager<br/><sub><i>open-source version</i></sub> | ❌ | ❌ | ❌ |
|RedissonSpringCacheManager<br/><sub><i>[Redisson PRO](https://redisson.pro) version</i></sub> | ❌ | ❌ | ✔️ |
|RedissonSpringLocalCachedCacheManager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ✔️ | ❌ | ✔️ |
|RedissonClusteredSpringCacheManager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ❌ | ✔️ | ✔️ |
|RedissonClusteredSpringLocalCachedCacheManager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ✔️ | ✔️ | ✔️ |
**Advanced eviction**
Allows to define `time to live` parameter per map entry. Doesn't use an entry eviction task, entries are cleaned on Redis or Valkey side.
Available implementations:
|Class name | Local<br/>cache | Data<br/>partitioning | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :----------:| :----------:|
|RedissonSpringCacheV2Manager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ❌ | ✔️ | ✔️ |
|RedissonSpringLocalCachedCacheV2Manager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ✔️ | ✔️ | ✔️ |
**Native eviction**
Allows to define `time to live` parameter per map entry. Doesn't use an entry eviction task, entries are cleaned on Redis side.
Requires **Redis 7.4+**.
Available implementations:
|Class name | Local<br/>cache | Data<br/>partitioning | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :----------:| :----------:|
|RedissonSpringCacheNativeManager<br/><sub><i>open-source version</i></sub> | ❌ | ❌ | ❌ |
|RedissonSpringCacheNativeManager<br/><sub><i>[Redisson PRO](https://redisson.pro) version</i></sub> | ❌ | ❌ | ✔️ |
|RedissonSpringLocalCachedCacheNativeManager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ✔️ | ❌ | ✔️ |
|RedissonClusteredSpringCacheNativeManager<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ❌ | ✔️ | ✔️ |
**Local cache**
Follow options object can be supplied during local cached managers initialization:
```java
LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
// Defines whether to store a cache miss into the local cache.
// Default value is false.
.storeCacheMiss(false);
// Defines store mode of cache data.
// Follow options are available:
// LOCALCACHE - store data in local cache only.
// LOCALCACHE_REDIS - store data in both Redis or Valkey and local cache.
.storeMode(StoreMode.LOCALCACHE_REDIS)
// Defines Cache provider used as local cache store.
// Follow options are available:
// REDISSON - uses Redisson own implementation
// CAFFEINE - uses Caffeine implementation
.cacheProvider(CacheProvider.REDISSON)
// Defines local cache eviction policy.
// Follow options are available:
// LFU - Counts how often an item was requested. Those that are used least often are discarded first.
// LRU - Discards the least recently used items first
// SOFT - Uses weak references, entries are removed by GC
// WEAK - Uses soft references, entries are removed by GC
// NONE - No eviction
.evictionPolicy(EvictionPolicy.NONE)
// If cache size is 0 then local cache is unbounded.
.cacheSize(1000)
// Used to load missed updates during any connection failures to Redis.
// Since, local cache updates can't be get in absence of connection to Redis.
// Follow reconnection strategies are available:
// CLEAR - Clear local cache if map instance has been disconnected for a while.
// LOAD - Store invalidated entry hash in invalidation log for 10 minutes
// Cache keys for stored invalidated entry hashes will be removed
// if LocalCachedMap instance has been disconnected less than 10 minutes
// or whole cache will be cleaned otherwise.
// NONE - Default. No reconnection handling
.reconnectionStrategy(ReconnectionStrategy.NONE)
// Used to synchronize local cache changes.
// Follow sync strategies are available:
// INVALIDATE - Default. Invalidate cache entry across all LocalCachedMap instances on map entry change
// UPDATE - Insert/update cache entry across all LocalCachedMap instances on map entry change
// NONE - No synchronizations on map changes
.syncStrategy(SyncStrategy.INVALIDATE)
// time to live for each map entry in local cache
.timeToLive(10000)
// or
.timeToLive(10, TimeUnit.SECONDS)
// max idle time for each map entry in local cache
.maxIdle(10000)
// or
.maxIdle(10, TimeUnit.SECONDS);
```
Each Spring Cache instance has two important parameters: `ttl` and `maxIdleTime` and stores data infinitely if they are not defined or equal to `0`.
Complete config example:
```java
@Configuration
@ComponentScan
@EnableCaching
public static class Application {
@Bean(destroyMethod="shutdown")
RedissonClient redisson() throws IOException {
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://127.0.0.1:7004", "redis://127.0.0.1:7001");
return Redisson.create(config);
}
@Bean
CacheManager cacheManager(RedissonClient redissonClient) {
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
// define local cache settings for "testMap" cache.
// ttl = 48 minutes and maxIdleTime = 24 minutes for local cache entries
LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
.evictionPolicy(EvictionPolicy.LFU)
.timeToLive(48, TimeUnit.MINUTES)
.maxIdle(24, TimeUnit.MINUTES);
.cacheSize(1000);
// create "testMap" Redis or Valkey cache with ttl = 24 minutes and maxIdleTime = 12 minutes
LocalCachedCacheConfig cfg = new LocalCachedCacheConfig(24*60*1000, 12*60*1000, options);
// Max size of map stored in Redis
cfg.setMaxSize(2000);
config.put("testMap", cfg);
return new RedissonSpringLocalCachedCacheManager(redissonClient, config);
// or
return new RedissonSpringLocalCachedCacheNativeManager(redissonClient, config);
// or
return new RedissonSpringLocalCachedCacheV2Manager(redissonClient, config);
// or
return new RedissonClusteredSpringLocalCachedCacheManager(redissonClient, config);
}
}
```
Cache configuration could be read from YAML configuration files:
```java
@Configuration
@ComponentScan
@EnableCaching
public static class Application {
@Bean(destroyMethod="shutdown")
RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.create(config);
}
@Bean
CacheManager cacheManager(RedissonClient redissonClient) throws IOException {
return new RedissonSpringLocalCachedCacheManager(redissonClient, "classpath:/cache-config.yaml");
}
}
```
### YAML config format
Below is the configuration of Spring Cache with name `testMap` in YAML format:
```yaml
---
testMap:
ttl: 1440000
maxIdleTime: 720000
localCacheOptions:
invalidationPolicy: "ON_CHANGE"
evictionPolicy: "NONE"
cacheSize: 0
timeToLiveInMillis: 0
maxIdleInMillis: 0
```
_Please note: `localCacheOptions` settings are available for `org.redisson.spring.cache.RedissonSpringLocalCachedCacheManager` and `org.redisson.spring.cache.RedissonSpringClusteredLocalCachedCacheManager` classes only._

@ -0,0 +1,37 @@
Client tracking listener is invoked when an invalidation message is received if the data previously requested has been changed. Next listener invocation will be made only if a new data request has been made and another change has occurred since then.
Available for [RBucket](data-and-services/objects.md/#object-holder), [RStream](data-and-services/objects.md/#stream), [RSet](data-and-services/objects.md/#set), [RMap](data-and-services/objects.md/#map), [RScoredSortedSet](data-and-services/collections.md/#scoredsortedset), [RList](data-and-services/collections.md/#list), [RQueue](data-and-services/collections.md/#queue), [RDeque](data-and-services/collections.md/#deque), [RBlockingQueue](data-and-services/collections.md/#blocking-queue), [RBlockingDeque](data-and-services/collections.md/#blocking-deque), [RDelayedQueue](data-and-services/collections.md/#delayed-queue), [RRingBuffer](data-and-services/collections.md/#ring-buffer) objects.
Requires [protocol](configuration.md) setting value set to `RESP3`.
Code usage example.
```java
RBucket<String> b = redisson.getBucket("test");
int listenerId = b.addListener(new TrackingListener() {
@Override
public void onChange(String name) {
// ...
}
});
// data requested and change is now tracked
b.get();
// ...
// stop tracking
b.removeListener(listenerId);
```
**Flush listener**
Flush listener is executed on flushall/flushdb commands execution.
```java
redisson.getKeys().addListener(new FlushListener() {
@Override
public void onFlush(InetSocketAddress address) {
// ...
}
});
```

@ -0,0 +1,209 @@
Redis or Valkey command|Sync / Async API<br/><sub>Redisson.create(config)</sub>|Reactive API<br/><sub>redisson.reactive()</sub>|RxJava3 API<br/><sub>redisson.rxJava()</sub>|
| --- | --- | --- | --- |
AUTH | Config.setPassword() | - | - |
APPEND | RBinaryStream.<br/>getOutputStream().write() | - | - |
BZPOPMAX|RScoredSortedSet.<br/>pollLast()<br/>pollLastAsync() | RScoredSortedSetReactive.<br/>pollLast()| RScoredSortedSetRx.<br/>pollLast() |
BZPOPMIN|RScoredSortedSet.<br/>pollFirst()<br/>pollFirstAsync() | RScoredSortedSetReactive.<br/>pollFirst() | RScoredSortedSetRx.<br/>pollFirst() |
BZMPOP|RScoredSortedSet.<br/>pollLast()<br/>pollLastAsync()<br/>pollLastFromAny()<br/>pollLastEntriesFromAny() | RScoredSortedSetReactive.<br/>pollLast()<br/>pollLastFromAny()<br/>pollLastEntriesFromAny()| RScoredSortedSetRx.<br/>pollLast()<br/>pollLastFromAny()<br/>pollLastEntriesFromAny() |
BITCOUNT|RBitSet.<br/>cardinality()<br/>cardinalityAsync() | RBitSetReactive.<br/>cardinality() | RBitSetRx.<br/>cardinality() |
BITOP|RBitSet.<br/>or()<br/>and()<br/>xor()<br/>orAsync()<br/>andAsync()<br/>xorAsync() | RBitSetReactive.<br/>or()<br/>and()<br/>xor() | RBitSetRx.<br/>or()<br/>and()<br/>xor() |
BITPOS|RBitSet.<br/>length()<br/>lengthAsync() | RBitSetReactive.<br/>length() | RBitSetRx.<br/>length() |
BITFIELD|RBitSet.<br/>getByte()<br/>setByte()<br/>incrementAndGetByte()<br/><br/>getShort()<br/>setShort()<br/>incrementAndGetShort()<br/><br/>getInteger()<br/>setInteger()<br/>incrementAndGetInteger()<br/><br/>getLong()<br/>setLong()<br/>incrementAndGetLong() | RBitSetReactive.<br/>getByte()<br/>setByte()<br/>incrementAndGetByte()<br/><br/>getShort()<br/>setShort()<br/>incrementAndGetShort()<br/><br/>getInteger()<br/>setInteger()<br/>incrementAndGetInteger()<br/><br/>getLong()<br/>setLong()<br/>incrementAndGetLong() | RBitSetRx.<br/>getByte()<br/>setByte()<br/>incrementAndGetByte()<br/><br/>getShort()<br/>setShort()<br/>incrementAndGetShort()<br/><br/>getInteger()<br/>setInteger()<br/>incrementAndGetInteger()<br/><br/>getLong()<br/>setLong()<br/>incrementAndGetLong() |
BLMPOP|RBlockingQueue.<br/>pollLastFromAny()<br/>pollFirstFromAny()<br/>pollLastFromAnyAsync()<br/>pollFirstFromAnyAsync() | RBlockingQueueReactive.<br/>pollLastFromAny()<br/>pollFirstFromAny() |RBlockingQueueRx.<br/>pollLastFromAny()<br/>pollFirstFromAny() |
BLPOP|RBlockingQueue.<br/>take()<br/>poll()<br/>pollFromAny()<br/>takeAsync()<br/>pollAsync()<br/>pollFromAnyAsync() | RBlockingQueueReactive.<br/>take()<br/>poll()<br/>pollFromAny() |RBlockingQueueRx.<br/>take()<br/>poll()<br/>pollFromAny() |
BLMOVE|RBlockingDeque.<br/>move()<br/>moveAsync()| RBlockingDequeReactive.<br/>move()|RBlockingDequeRx.<br/>move()|
BRPOP|RBlockingDeque.<br/>takeLast()<br/>takeLastAsync() | RBlockingDequeReactive.<br/>takeLast() | RBlockingDequeRx.<br/>takeLast() |
BRPOPLPUSH|RBlockingQueue.<br/>pollLastAndOfferFirstTo()<br/>pollLastAndOfferFirstToAsync() | RBlockingQueueReactive.<br/>pollLastAndOfferFirstTo()| RBlockingQueueRx.<br/>pollLastAndOfferFirstTo()|
CONFIG GET|RedisNode.<br/>setConfig()<br/>setConfigAsync() | - | - |
CONFIG SET|RedisNode.<br/>getConfig()<br/>getConfigAsync() | - | - |
COPY|RObject.<br/>copy()<br/>copyAsync() | RObjectReactive.<br/>copy() | RObjectRx.<br/>copy() |
CLIENT SETNAME|Config.setClientName() | - | - |
CLIENT REPLY|BatchOptions.skipResult() | - | - |
CLIENT TRACKING|RBucket<br/>.addListener(TrackingListener)<br/>RStream<br/>.addListener(TrackingListener)<br/>RScoredSortedSet<br/>.addListener(TrackingListener)<br/>RSet<br/>.addListener(TrackingListener)<br/>RMap<br/>.addListener(TrackingListener) | RBucketReactive<br/>.addListener(TrackingListener)<br/>RStreamReactive<br/>.addListener(TrackingListener)<br/>RScoredSortedSetReactive<br/>.addListener(TrackingListener)<br/>RSetReactive<br/>.addListener(TrackingListener)<br/>RMapReactive<br/>.addListener(TrackingListener) | RBucketRx<br/>.addListener(TrackingListener)<br/>RStreamRx<br/>.addListener(TrackingListener)<br/>RScoredSortedSetRx<br/>.addListener(TrackingListener)<br/>RSetRx<br/>.addListener(TrackingListener)<br/>RMapRx<br/>.addListener(TrackingListener) |
CLUSTER INFO| ClusterNode.info() | - | - |
CLUSTER KEYSLOT|RKeys.<br/>getSlot()<br/>getSlotAsync() | RKeysReactive.<br/>getSlot() | RKeysRx.<br/>getSlot() |
CLUSTER NODES|Used in ClusterConnectionManager |
DECRBY|RAtomicLong.<br/>addAndGet()<br/>addAndGetAsync() | RAtomicLongReactive.<br/>addAndGet() |RAtomicLongRx.<br/>addAndGet() |
DUMP|RObject.<br/>dump()<br/>dumpAsync()| RObjectReactive.<br/>dump()| RObjectRx.<br/>dump()|
DBSIZE|RKeys.<br/>count()<br/>countAsync()| RKeysReactive.<br/>count()| RKeysRx.count()|
DECR|RAtomicLong.<br/>decrementAndGet()<br/>decrementAndGetAsync()| RAtomicLongReactive.<br/>decrementAndGet()| RAtomicLongRx.<br/>decrementAndGet()|
DEL|RObject.<br/>delete()<br/>deleteAsync()<br/><br/>RKeys.<br/>delete()<br/>deleteAsync()| RObjectReactive.<br/>delete()<br/><br/>RKeysReactive.<br/>delete()|RObjectRx.<br/>delete()<br/><br/>RKeysRx.<br/>delete()|
STRLEN|RBucket.<br/>size()<br/>sizeAsync()| RBucketReactive.<br/>size()| RBucketRx.<br/>size()|
EVAL|RScript.<br/>eval()<br/>evalAsync()| RScriptReactive.<br/>eval()| RScriptRx.<br/>eval()|
EVALSHA|RScript.<br/>evalSha()<br/>evalShaAsync()| RScriptReactive.<br/>evalSha()| RScriptRx.<br/>evalSha()|
EXEC|RBatch.<br/>execute()<br/>executeAsync()| RBatchReactive.<br/>execute()| RBatchRx.<br/>execute()|
EXISTS|RObject.<br/>isExists()<br/>isExistsAsync()| RObjectReactive.<br/>isExists()| RObjectRx.<br/>isExists()|
FLUSHALL|RKeys.<br/>flushall()<br/>flushallAsync()| RKeysReactive.<br/>flushall()| RKeysRx.<br/>flushall()|
FLUSHDB|RKeys.<br/>flushdb()<br/>flushdbAsync()| RKeysReactive.<br/>flushdb()| RKeysRx.<br/>flushdb()|
GETRANGE|RBinaryStream.<br/>getChannel().read()|RBinaryStreamReactive.<br/>read()|RBinaryStreamRx.<br/>read()|
GEOADD|RGeo.<br/>add()<br/>addAsync()| RGeoReactive.<br/>add()| RGeoRx.<br/>add()|
GEODIST|RGeo.<br/>dist()<br/>distAsync()| RGeoReactive.<br/>dist()| RGeoRx.<br/>dist()|
GEOHASH|RGeo.<br/>hash()<br/>hashAsync()| RGeoReactive.<br/>hash()| RGeoRx.<br/>hash()|
GEOPOS|RGeo.<br/>pos()<br/>posAsync()| RGeoReactive.<br/>pos()| RGeoRx.<br/>pos()|
GEORADIUS|RGeo.<br/>radius()<br/>radiusAsync()<br/>radiusWithDistance()<br/>radiusWithDistanceAsync()<br/>radiusWithPosition()<br/>radiusWithPositionAsync()|RGeoReactive.<br/>radius()<br/>radiusWithDistance()<br/>radiusWithPosition()|RGeoRx.<br/>radius()<br/>radiusWithDistance()<br/>radiusWithPosition()|
GEOSEARCH|RGeo.<br/>search()<br/>searchAsync()| RGeoReactive.<br/>search()| RGeoRx.<br/>search()|
GEOSEARCHSTORE|RGeo.<br/>storeSearchTo()<br/>storeSearchToAsync()| RGeoReactive.<br/>storeSearchTo()| RGeoRx.<br/>storeSearchTo()|
GET|RBucket.<br/>get()<br/>getAsync()<br/><br/>RBinaryStream.<br/>get()<br/>getAsync()| RBucketReactive.<br/>get()<br/><br/>RBinaryStreamReactive.<br/>get()| RBucketRx.<br/>get()<br/><br/>RBinaryStreamRx.<br/>get()|
GETEX|RBucket.<br/>getAndExpire()<br/>getAndExpireAsync()<br/>getAndClearExpire()<br/>getAndClearExpireAsync()| RBucketReactive.<br/>getAndExpire()<br/>getAndClearExpire()| RBucketRx.<br/>getAndExpire()<br/>getAndClearExpire()|
GETBIT|RBitSet.<br/>get()<br/>getAsync()| RBitSetReactive.<br/>get()| RBitSetRx.<br/>get() |
GETSET|RBucket.<br/>getAndSet()<br/>getAndSetAsync()<br/><br/>RAtomicLong.<br/>getAndSet()<br/>getAndSetAsync()<br/><br/>RAtomicDouble.<br/>getAndSet()<br/>getAndSetAsync()|RBucketReactive.<br/>getAndSet()<br/><br/>RAtomicLongReactive.<br/>getAndSet()<br/><br/>RAtomicDoubleReactive.<br/>getAndSet()|RBucketRx.<br/>getAndSet()<br/><br/>RAtomicLongRx.<br/>getAndSet()<br/><br/>RAtomicDoubleRx.<br/>getAndSet()
HDEL|RMap.<br/>fastRemove()<br/>fastRemoveAsync()| RMapReactive.<br/>fastRemove()| RMapRx.<br/>fastRemove()|
HEXISTS|RMap.<br/>containsKey()<br/>containsKeyAsync()| RMapReactive.<br/>containsKey()| RMapRx.<br/>containsKey()|
HGET|RMap.<br/>get()<br/>getAsync()|RMapReactive.<br/>get()|RMapRx.<br/>get()|
HSTRLEN|RMap.<br/>valueSize()<br/>valueSizeAsync()|RMapReactive.<br/>valueSize()| RMapRx.<br/>valueSize()|
HGETALL|RMap.<br/>readAllEntrySet()<br/>readAllEntrySetAsync()|RMapReactive.<br/>readAllEntrySet()| RMapRx.<br/>readAllEntrySet()|
HINCRBY|RMap.<br/>addAndGet()<br/>addAndGetAsync()| RMapReactive.<br/>addAndGet()| RMapRx.<br/>addAndGet()|
HINCRBYFLOAT|RMap.<br/>addAndGet()<br/>addAndGetAsync()| RMapReactive.<br/>addAndGet()| RMapRx.<br/>addAndGet()|
HKEYS|RMap.<br/>readAllKeySet()<br/>readAllKeySetAsync()| RMapReactive.<br/>readAllKeySet()| RMapRx.<br/>readAllKeySet()|
HLEN|RMap.<br/>size()<br/>sizeAsync()| RMapReactive.<br/>size()| RMapRx.<br/>size()|
HMGET|RMap.<br/>getAll()<br/>getAllAsync()| RMapReactive.<br/>getAll()| RMapRx.<br/>getAll()|
HMSET|RMap.<br/>putAll()<br/>putAllAsync()| RMapReactive.<br/>putAll()| RMapRx.<br/>putAll()|
HRANDFIELD|RMap.<br/>putAll()<br/>putAllAsync()| RMapReactive.<br/>putAll()| RMapRx.<br/>putAll()|
HSCAN|RMap.<br/>keySet().iterator()<br/>values().iterator()<br/>entrySet().iterator()|RMapReactive.<br/>keyIterator()<br/>valueIterator()<br/>entryIterator()|RMapRx.<br/>keyIterator()<br/>valueIterator()<br/>entryIterator()|
HSET|RMap.<br/>randomEntries()<br/>randomKeys()<br/>randomEntriesAsync()<br/>randomKeysAsync()| RMapReactive.<br/>randomEntries()<br/>randomKeys()| RMapRx.<br/>randomEntries()<br/>randomKeys()|
HSETNX|RMap.<br/>fastPutIfAbsent()<br/>fastPutIfAbsentAsync()| RMapReactive.<br/>fastPutIfAbsent()| RMapRx.<br/>fastPutIfAbsent()|
HVALS|RMap.<br/>readAllValues()<br/>readAllValuesAsync()| RMapReactive.<br/>readAllValues()| RMapRx.<br/>readAllValues()|
HPEXPIRE|RMapCacheNative.<br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()<br/>putAsync()<br/>fastPutAsync()<br/>putIfAbsentAsync()<br/>fastPutIfAbsentAsync()<br/>putAllAsync()<br/>expireEntryAsync()| RMapCacheNativeReactive.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()| RMapCacheNativeRx.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()|
HPEXPIREAT|RMapCacheNative.<br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()<br/>putAsync()<br/>fastPutAsync()<br/>putIfAbsentAsync()<br/>fastPutIfAbsentAsync()<br/>putAllAsync()<br/>expireEntryAsync()| RMapCacheNativeReactive.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()| RMapCacheNativeRx.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()|
HEXPIRE|RMapCacheNative.<br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()<br/>putAsync()<br/>fastPutAsync()<br/>putIfAbsentAsync()<br/>fastPutIfAbsentAsync()<br/>putAllAsync()<br/>expireEntryAsync()| RMapCacheNativeReactive.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()| RMapCacheNativeRx.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()|
HEXPIREAT|RMapCacheNative.<br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()<br/>putAsync()<br/>fastPutAsync()<br/>putIfAbsentAsync()<br/>fastPutIfAbsentAsync()<br/>putAllAsync()<br/>expireEntryAsync()| RMapCacheNativeReactive.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()| RMapCacheNativeRx.<br/><br/>put()<br/>fastPut()<br/>putIfAbsent()<br/>fastPutIfAbsent()<br/>putAll()<br/>expireEntry()|
HPERSIST|RMapCacheNative.<br/>clearExpire()<br/>clearExpireAsync()| RMapCacheNativeReactive.<br/>clearExpire()| RMapCacheNativeRx.<br/>clearExpire()|
HPTTL|RMapCacheNative.<br/>remainTimeToLive()<br/>remainTimeToLiveAsync()| RMapCacheNativeReactive.<br/>remainTimeToLive()| RMapCacheNativeRx.<br/>remainTimeToLive()|
INCR|RAtomicLong.<br/>incrementAndGet()<br/>incrementAndGetAsync()| RAtomicLongReactive.<br/>incrementAndGet()| RAtomicLongRx.<br/>incrementAndGet()|
INCRBY|RAtomicLong.<br/>addAndGet()<br/>addAndGetAsync()| RAtomicLongReactive.<br/>addAndGet()| RAtomicLongRx.<br/>addAndGet()|
INCRBYFLOAT|RAtomicDouble.<br/>addAndGet()<br/>addAndGetAsync()| RAtomicDoubleReactive.<br/>addAndGet()| RAtomicDoubleRx.<br/>addAndGet()|
JSON.ARRAPPEND|RJsonBucket.<br/>arrayAppend()<br/>arrayAppendAsync()| RJsonBucketReactive.<br/>arrayAppend()| RJsonBucketRx.<br/>arrayAppend()|
JSON.ARRINDEX|RJsonBucket.<br/>arrayIndex()<br/>arrayIndexAsync()| RJsonBucketReactive.<br/>arrayIndex()| RJsonBucketRx.<br/>arrayIndex()|
JSON.ARRINSERT|RJsonBucket.<br/>arrayInsert()<br/>arrayInsertAsync()| RJsonBucketReactive.<br/>arrayInsert()| RJsonBucketRx.<br/>arrayInsert()|
JSON.ARRLEN|RJsonBucket.<br/>arraySize()<br/>arraySizeAsync()| RJsonBucketReactive.<br/>arraySize()| RJsonBucketRx.<br/>arraySize()|
JSON.ARRPOP|RJsonBucket.<br/>arrayPollLast()<br/>arrayPollFirst()<br/>arrayPop()<br/>arrayPollLastAsync()<br/>arrayPollFirstAsync()<br/>arrayPopAsync()| RJsonBucketReactive.<br/>arrayPollLast()<br/>arrayPollFirst()<br/>arrayPop()| RJsonBucketRx.<br/>arrayPollLast()<br/>arrayPollFirst()<br/>arrayPop()|
JSON.ARRTRIM|RJsonBucket.<br/>arrayTrim()<br/>arrayTrimAsync()| RJsonBucketReactive.<br/>arrayTrim()| RJsonBucketRx.<br/>arrayTrim()|
JSON.CLEAR|RJsonBucket.<br/>clear()<br/>clearAsync()| RJsonBucketReactive.<br/>clear()| RJsonBucketRx.<br/>clear()|
JSON.GET|RJsonBucket.<br/>get()<br/>getAsync()| RJsonBucketReactive.<br/>get()| RJsonBucketRx.<br/>get()|
JSON.MERGE|RJsonBucket.<br/>merge()<br/>mergeAsync()| RJsonBucketReactive.<br/>merge()| RJsonBucketRx.<br/>merge()|
JSON.NUMINCRBY|RJsonBucket.<br/>incrementAndGet()<br/>incrementAndGetAsync()| RJsonBucketReactive.<br/>incrementAndGet()| RJsonBucketRx.<br/>incrementAndGet()|
JSON.OBJLEN|RJsonBucket.<br/>countKeys()<br/>countKeysAsync()| RJsonBucketReactive.<br/>countKeys()| RJsonBucketRx.<br/>countKeys()|
JSON.OBJKEYS|RJsonBucket.<br/>getKeys()<br/>getKeysAsync()| RJsonBucketReactive.<br/>getKeys()| RJsonBucketRx.<br/>getKeys()|
JSON.SET|RJsonBucket.<br/>set()<br/>setAsync()| RJsonBucketReactive.<br/>set()| RJsonBucketRx.<br/>set()|
JSON.STRAPPEND|RJsonBucket.<br/>stringAppend()<br/>stringAppendAsync()| RJsonBucketReactive.<br/>stringAppend()| RJsonBucketRx.<br/>stringAppend()|
JSON.STRLEN|RJsonBucket.<br/>stringSize()<br/>stringSizeAsync()| RJsonBucketReactive.<br/>stringSize()| RJsonBucketRx.<br/>stringSize()|
JSON.TOGGLE|RJsonBucket.<br/>toggle()<br/>toggleAsync()| RJsonBucketReactive.<br/>toggle()| RJsonBucketRx.<br/>toggle()|
JSON.TYPE|RJsonBucket.<br/>type()<br/>typeAsync()| RJsonBucketReactive.<br/>type()| RJsonBucketRx.<br/>type()|
KEYS|RKeys.<br/>getKeysByPattern()<br/>getKeysByPatternAsync()| RKeysReactive.<br/>getKeysByPattern()| RKeysRx.<br/>getKeysByPattern()|
LINDEX|RList.<br/>get()<br/>getAsync()| RListReactive.<br/>get()|RListRx.<br/>get()|
LLEN|RList.<br/>size()<br/>sizeAsync()| RListReactive.<br/>size()|RListRx.<br/>size()|
LMOVE|RDeque.<br/>move()<br/>moveAsync()| RDequeReactive.<br/>move()|RDequeRx.<br/>move()|
LPOP|RQueue.<br/>poll()<br/>pollAsync()| RQueueReactive.<br/>poll()|RQueueRx.<br/>poll()|
LPUSH|RDeque.<br/>addFirst()<br/>addFirstAsync()|RDequeReactive.<br/>addFirst()||RDequeRx.<br/>addFirst()|
LRANGE|RList.<br/>readAll()<br/>readAllAsync()|RListReactive.readAll()|RListRx.readAll()|
LPUSHX|RDeque.<br/>addFirstIfExists()<br/>addFirstIfExistsAsync()|RDequeReactive.<br/>addFirstIfExists()|RDequeRx.<br/>addFirstIfExists()|
LREM|RList.<br/>fastRemove()<br/>fastRemoveAsync()|RListReactive.<br/>fastRemove()|RListRx.<br/>fastRemove()|
LSET|RList.<br/>fastSet()<br/>fastSetAsync()|RListReactive.<br/>fastSet()|RListRx.<br/>fastSet()|
LTRIM|RList.<br/>trim()<br/>trimAsync()|RListReactive.<br/>trim()|RListRx.<br/>trim()|
LINSERT|RList.<br/>addBefore()<br/>addAfter()<br/>addBeforeAsync()<br/>addAfterAsync()|RListReactive.<br/>addBefore()<br/>addAfter()|RListRx.<br/>addBefore()<br/>addAfter()|
MULTI|RBatch.<br/>execute()<br/>executeAsync()|RBatchReactive.<br/>execute()|RBatchRx.<br/>execute()|
MGET|RBuckets.<br/>get()<br/>getAsync()|RBucketsReactive.<br/>get()|RBucketsRx.<br/>get()|
MSETNX|RBuckets.<br/>trySet()<br/>trySetAsync()|RBucketsReactive.<br/>trySet()|RBucketsRx.<br/>trySet()|
MIGRATE|RObject.<br/>migrate()<br/>migrateAsync()|RObjectReactive.<br/>migrate()|RObjectRx.<br/>migrate()|
MOVE|RObject.<br/>move()<br/>moveAsync()|RObjectReactive.<br/>move()|RObjectRx.<br/>move()|
MSET|RBuckets.<br/>set()<br/>setAsync()|RBucketsReactive.<br/>set()|RBucketsRx.<br/>set()|
PERSIST|RExpirable.<br/>clearExpire()<br/>clearExpireAsync()|RExpirableReactive.<br/>clearExpire()|RExpirableRx.<br/>clearExpire()|
PEXPIRE|RExpirable.<br/>expire()<br/>expireAsync()|RExpirableReactive.<br/>expire()|RExpirableRx.<br/>expire()|
PEXPIREAT|RExpirable.<br/>expireAt()<br/>expireAtAsync()|RExpirableReactive.<br/>expireAt()|RExpirableRx.<br/>expireAt()|
PEXPIRETIME|RExpirable.<br/>expireTime()<br/>expireTimeAsync()|RExpirableReactive.<br/>expireTime()|RExpirableRx.<br/>expireTime()|
PFADD|RHyperLogLog.<br/>add()<br/>addAsync()<br/>addAll()<br/>addAllAsync()|RHyperLogLogReactive.<br/>add()<br/><br/>addAll()|RHyperLogLogRx.<br/>add()<br/><br/>addAll()|
PFCOUNT|RHyperLogLog.<br/>count()<br/>countAsync()<br/>countWith()<br/>countWithAsync()|RHyperLogLogReactive.<br/>count()<br/>countWith()|RHyperLogLogRx.<br/>count()<br/>countWith()|
PFMERGE|RHyperLogLog.<br/>mergeWith()<br/>mergeWithAsync()|RHyperLogLogReactive.<br/>mergeWith()|RHyperLogLogRx.<br/>mergeWith()|
PING|Node.ping()<br/>NodesGroup.pingAll()| - | - |
PSUBSCRIBE|RPatternTopic.<br/>addListener()|RPatternTopicReactive.<br/>addListener()|RPatternTopicRx.<br/>addListener()|
PSETEX|RBucket.<br/>set()<br/>setAsync()|RBucketReactive.<br/>set()|RBucketRx.<br/>set()|
PTTL|RExpirable.<br/>remainTimeToLive()<br/>remainTimeToLiveAsync()|RExpirableReactive.<br/>remainTimeToLive()|RExpirableRx.<br/>remainTimeToLive()|
PUBLISH|RTopic.<br/>publish()|RTopicReactive.<br/>publish()|RTopicRx.<br/>publish()|
PUBSUB NUMSUB|RTopic.<br/>countSubscribers()<br/>countSubscribersAsync()|RTopicReactive.<br/>countSubscribers()|RTopicRx.<br/>countSubscribers()|
PUNSUBSCRIBE|RPatternTopic.<br/>removeListener()|RPatternTopicReactive.<br/>removeListener()|RPatternTopicRx.<br/>removeListener()|
RANDOMKEY|RKeys.<br/>randomKey()<br/>randomKeyAsync()|RKeysReactive.<br/>randomKey()|RKeysRx.<br/>randomKey()|
RESTORE|RObject.<br/>restore()<br/>restoreAsync()|RObjectReactive.<br/>restore()|RObjectRx.<br/>restore()|
RENAME|RObject.<br/>rename()<br/>renameAsync()|RObjectReactive.<br/>rename()|RObjectRx.<br/>rename()|
RPOP|RDeque.<br/>pollLast()<br/>removeLast()<br/>pollLastAsync()<br/>removeLastAsync()|RDequeReactive.<br/>pollLast()<br/>removeLast()|RDequeRx.<br/>pollLast()<br/>removeLast()|
RPOPLPUSH|RDeque.<br/>pollLastAndOfferFirstTo()<br/>pollLastAndOfferFirstToAsync()|RDequeReactive.<br/>pollLastAndOfferFirstTo()|RDequeRx.<br/>pollLastAndOfferFirstTo()|
RPUSH|RList.<br/>add()<br/>addAsync()|RListReactive.<br/>add()|RListRx.<br/>add()|
RPUSHX|RDeque.<br/>addLastIfExists()<br/>addLastIfExistsAsync()|RListReactive.<br/>addLastIfExists()|RListRx.<br/>addLastIfExists()|
SADD|RSet.<br/>add()<br/>addAsync()|RSetReactive.<br/>add()|RSetRx.<br/>add()|
SETRANGE|RBinaryStream.<br/>getChannel().write()|RBinaryStreamReactive.<br/>write()|RBinaryStreamRx.<br/>write()|
SCAN|RKeys.<br/>getKeys()|RKeysReactive.<br/>getKeys()|RKeysRx.<br/>getKeys()|
SCARD|RSet.<br/>size()<br/>sizeAsync()|RSetReactive.<br/>size()|RSetRx.<br/>size()|
SCRIPT EXISTS|RScript.<br/>scriptExists()<br/>scriptExistsAsync()|RScriptReactive.<br/>scriptExists()|RScriptRx.<br/>scriptExists()|
SCRIPT FLUSH|RScript.<br/>scriptFlush()<br/>scriptFlushAsync()|RScriptReactive.<br/>scriptFlush()|RScriptRx.<br/>scriptFlush()|
SCRIPT KILL|RScript.<br/>scriptKill()<br/>scriptKillAsync()|RScriptReactive.<br/>scriptKill()|RScriptRx.<br/>scriptKill()|
SCRIPT LOAD|RScript.<br/>scriptLoad()<br/>scriptLoadAsync()|RScriptReactive.<br/>scriptLoad()|RScriptRx.<br/>scriptLoad()|
SDIFFSTORE|RSet.<br/>diff()<br/>diffAsync()|RSetReactive.<br/>diff()|RSetRx.<br/>diff()|
SDIFF|RSet.<br/>readDiff()<br/>readDiffAsync()|RSetReactive.<br/>readDiff()|RSetRx.<br/>readDiff()|
SRANDMEMBER|RSet.<br/>random()<br/>randomAsync()|RSetReactive.<br/>random()|RSetRx.<br/>random()|
SELECT|Config.setDatabase()| - | - |
SET|RBucket.<br/>set()<br/>setAsync()|RBucketReactive.<br/>set()|RBucketRx.<br/>set()|
SETBIT|RBitSet.<br/>set()<br/>clear()<br/>setAsync()<br/>clearAsync()|RBitSetReactive.<br/>set()<br/>clear()|RBitSetRx.<br/>set()<br/>clear()|
SETEX|RBucket.<br/>set()<br/>setAsync()|RBucketReactive.<br/>set()|RBucketRx.<br/>set()|
SETNX|RBucket.<br/>setIfAbsent()<br/>setIfAbsentAsync()|RBucketReactive.<br/>setIfAbsent()|RBucketRx.<br/>setIfAbsent()|
SISMEMBER|RSet.<br/>contains()<br/>containsAsync()|RSetReactive.<br/>contains()|RSetRx.<br/>contains()|
SINTERSTORE|RSet.<br/>intersection()<br/>intersectionAsync()|RSetReactive.<br/>intersection()|RSetRx.<br/>intersection()|
SINTER|RSet.<br/>readIntersection()<br/>readIntersectionAsync()|RSetReactive.<br/>readIntersection()|RSetRx.<br/>readIntersection()|
SMEMBERS|RSet.<br/>readAll()<br/>readAllAsync()|RSetReactive.<br/>readAll()|RSetRx.<br/>readAll()|
SMOVE|RSet.<br/>move()<br/>moveAsync()|RSetReactive.<br/>move()|RSetRx.<br/>move()|
SORT|RList.<br/>readSort()<br/>sortTo()<br/>readSortAsync()<br/>sortToAsync()|RListReactive.<br/>readSort()<br/>sortTo()|RListRx.<br/>readSort()<br/>sortTo()|
SPOP|RSet.<br/>removeRandom()<br/>removeRandomAsync()|RSetReactive.<br/>removeRandom()|RSetRx.<br/>removeRandom()|
SREM|RSet.<br/>remove()<br/>removeAsync()|RSetReactive.<br/>remove()|RSetRx.<br/>remove()|
SSCAN|RSet.<br/>iterator()|RSetReactive.<br/>iterator()|RSetRx.<br/>iterator()|
SUBSCRIBE|RTopic.<br/>addListener()|RTopicReactive.<br/>addListener()|RTopicRx.<br/>addListener()|
SUNION|RSet.<br/>readUnion()<br/>readUnionAsync()|RSetReactive.<br/>readUnion()|RSetRx.<br/>readUnion()|
SUNIONSTORE|RSet.<br/>union()<br/>unionAsync()|RSetReactive.<br/>union()|RSetRx.<br/>union()|
SWAPDB|RKeys.<br/>swapdb()<br/>swapdbAsync()|RKeysReactive.<br/>swapdb()|RKeysRx.<br/>swapdb()|
TTL|RExpirable.<br/>remainTimeToLive()<br/>remainTimeToLiveAsync()|RExpirableReactive.<br/>remainTimeToLive()|RExpirableRx.<br/>remainTimeToLive()|
TYPE|RKeys.<br/>getType()<br/>getTypeAsync()|RKeysReactive.<br/>getType()|RKeysRx.<br/>getType()|
TOUCH|RObject.<br/>touch()<br/>touchAsync()|RObjectReactive.<br/>touch()|RObjectRx.<br/>touch()|
UNSUBSCRIBE|RTopic.<br/>removeListener()|RTopicReactive.<br/>removeListener()|RTopicRx.<br/>removeListener()|
UNLINK|RObject.<br/>unlink()<br/>unlinkAsync()|RObjectReactive.<br/>unlink()|RObjectRx.<br/>unlink()|
WAIT|BatchOptions.<br/>sync()|BatchOptions.<br/>sync()|BatchOptions.<br/>sync()|
WAITAOF|BatchOptions.<br/>syncAOF()|BatchOptions.<br/>syncAOF()|BatchOptions.<br/>syncAOF()|
ZADD|RScoredSortedSet.<br/>add()<br/>addAsync()<br/>addAll()<br/>addAllAsync()|RScoredSortedSetReactive.<br/>add()<br/>addAll()|RScoredSortedSetRx.<br/>add()<br/>addAll()|
ZCARD|RScoredSortedSet.<br/>size()<br/>sizeAsync()|RScoredSortedSetReactive.<br/>size()|RScoredSortedSetRx.<br/>size()|
ZCOUNT|RScoredSortedSet.<br/>count()<br/>countAsync()|RScoredSortedSetReactive.<br/>count()|RScoredSortedSetRx.<br/>count()|
ZDIFF|RScoredSortedSet.<br/>readDiff()<br/>readDiffAsync()|RScoredSortedSetReactive.<br/>readDiff()|RScoredSortedSetRx.<br/>readDiff()|
ZDIFFSTORE|RScoredSortedSet.<br/>diff()<br/>diffAsync()|RScoredSortedSetReactive.<br/>diff()|RScoredSortedSetRx.<br/>diff()|
ZINCRBY|RScoredSortedSet.<br/>addScore()<br/>addScoreAsync()|RScoredSortedSetReactive.<br/>addScore()|RScoredSortedSetRx.<br/>addScore()|
ZINTER|RScoredSortedSet.<br/>readIntersection()<br/>readIntersectionAsync()|RScoredSortedSetReactive.<br/>readIntersection()|RScoredSortedSetRx.<br/>readIntersection()|
ZREMRANGEBYRANK|RScoredSortedSet.<br/>removeRangeByRank()<br/>removeRangeByRankAsync()|RScoredSortedSetReactive.<br/>removeRangeByRank()|RScoredSortedSetRx.<br/>removeRangeByRank()|
ZREVRANGEBYLEX|RLexSortedSet.<br/>rangeReversed()<br/>rangeReversedAsync()|RLexSortedSetReactive.<br/>rangeReversed()|RLexSortedSetSetRx.<br/>rangeReversed()|
ZLEXCOUNT|RLexSortedSet.<br/>lexCount()<br/>lexCountHead()<br/>lexCountTail()<br/>lexCountAsync()<br/>lexCountHeadAsync()<br/>lexCountTailAsync()|RLexSortedSetReactive.<br/>lexCount()<br/>lexCountHead()<br/>lexCountTail()|RLexSortedSetRx.<br/>lexCount()<br/>lexCountHead()<br/>lexCountTail()|
ZRANGE|RScoredSortedSet.<br/>valueRange()<br/>valueRangeAsync()|RScoredSortedSetReactive.<br/>valueRange()|RScoredSortedSetRx.<br/>valueRange()|
ZRANDMEMBER|RScoredSortedSet.<br/>random()<br/>randomAsync()|RScoredSortedSetReactive.<br/>random()|RScoredSortedSetRx.<br/>random()|
ZREVRANGE|RScoredSortedSet.<br/>valueRangeReversed()<br/>valueRangeReversedAsync()|RScoredSortedSetReactive.<br/>valueRangeReversed()|RScoredSortedSetRx.<br/>valueRangeReversed()|
ZUNION|RScoredSortedSet.<br/>readUnion()<br/>readUnionAsync()|RScoredSortedSetReactive.<br/>readUnion()|RScoredSortedSetRx.<br/>readUnion()|
ZUNIONSTORE|RScoredSortedSet.<br/>union()<br/>unionAsync()|RScoredSortedSetReactive.<br/>union()|RScoredSortedSetRx.<br/>union()|
ZINTERSTORE|RScoredSortedSet.<br/>intersection()<br/>intersectionAsync()|RScoredSortedSetReactive.<br/>intersection()|RScoredSortedSetRx.<br/>intersection()|
ZPOPMAX|RScoredSortedSet.<br/>pollLast()<br/>pollLastAsync()|RScoredSortedSetReactive.<br/>pollLast()|RScoredSortedSetRx.<br/>pollLast()|
ZPOPMIN|RScoredSortedSet.<br/>pollFirst()<br/>pollFirstAsync()|RScoredSortedSetReactive.<br/>pollFirst()|RScoredSortedSetRx.<br/>pollFirst()|
ZMPOP|RScoredSortedSet.<br/>pollFirstEntriesFromAny()<br/>pollFirstEntriesFromAnyAsync()<br/>pollLastFromAny()<br/>pollLastFromAnyAsync()<br/>pollFirstFromAny()<br/>pollFirstFromAnyAsync()|RScoredSortedSetReactive.<br/>pollFirstEntriesFromAny()<br/>pollLastFromAny()<br/>pollFirstFromAny()|RScoredSortedSetRx.<br/>pollFirstEntriesFromAny()<br/>pollLastFromAny()<br/>pollFirstFromAny()|
ZRANGEBYLEX|RLexSortedSet.<br/>range()<br/>rangeHead()<br/>rangeTail()<br/>rangeAsync()<br/>rangeHeadAsync()<br/>rangeTailAsync()|RLexSortedSetReactive.<br/>range()<br/>rangeHead()<br/>rangeTail()|RLexSortedSetRx.<br/>range()<br/>rangeHead()<br/>rangeTail()|
ZRANGEBYSCORE|RScoredSortedSet.<br/>valueRange()<br/>entryRange()<br/>valueRangeAsync()<br/>entryRangeAsync()|RScoredSortedSetReactive.<br/>valueRange()<br/>entryRange()|RScoredSortedSetRx.<br/>valueRange()<br/>entryRange()|
TIME|RedissonClient.<br/>getNodesGroup().<br/>getNode().time()<br/>getClusterNodesGroup().<br/>getNode().time()| - | - |
ZRANK|RScoredSortedSet.<br/>rank()<br/>rankAsync()|RScoredSortedSetReactive.<br/>rank()|RScoredSortedSetRx.<br/>rank()|
ZREM|RScoredSortedSet.<br/>remove()<br/>removeAll()<br/>removeAsync()<br/>removeAllAsync()|RScoredSortedSetReactive.<br/>remove()<br/>removeAll()|RScoredSortedSetRx.<br/>remove()<br/>removeAll()|
ZREMRANGEBYLEX|RLexSortedSet.<br/>removeRange()<br/>removeRangeHead()<br/>removeRangeTail()<br/>removeRangeAsync()<br/>removeRangeHeadAsync()<br/>removeRangeTailAsync()|RLexSortedSetReactive.<br/>removeRange()<br/>removeRangeHead()<br/>removeRangeTail()|RLexSortedSetRx.<br/>removeRange()<br/>removeRangeHead()<br/>removeRangeTail()|
ZREMRANGEBYSCORE|RScoredSortedSet.<br/>removeRangeByScore()<br/>removeRangeByScoreAsync()|RScoredSortedSetReactive.<br/>removeRangeByScore()|RScoredSortedSetRx.<br/>removeRangeByScore()|
ZREVRANGEBYSCORE|RScoredSortedSet.<br/>valueRangeReversed()<br/>entryRangeReversed()<br/>valueRangeReversedAsync()<br/>entryRangeReversedAsync()|RScoredSortedSetReactive.<br/>entryRangeReversed()<br/>valueRangeReversed()|RScoredSortedSetRx.<br/>entryRangeReversed()<br/>valueRangeReversed()|
ZREVRANK|RScoredSortedSet.<br/>revRank()<br/>revRankAsync()|RScoredSortedSetReactive.<br/>revRank()|RScoredSortedSetRx.<br/>revRank()|
ZSCORE|RScoredSortedSet.<br/>getScore()<br/>getScoreAsync()|RScoredSortedSetReactive.<br/>getScore()|RScoredSortedSetRx.<br/>getScore()|
XACK|RStream.<br/>ack()<br/>ackAsync()|RStreamReactive.<br/>ack()|RStreamRx.<br/>ack()|
XADD|RStream.<br/>add()<br/>addAsync()|RStreamReactive.<br/>add()|RStreamRx.<br/>add()|
XAUTOCLAIM|RStream.<br/>autoClaim()<br/>autoClaimAsync()|RStreamReactive.<br/>autoClaim()|RStreamRx.<br/>autoClaim()|
XCLAIM|RStream.<br/>claim()<br/>claimAsync()|RStreamReactive.<br/>claim()|RStreamRx.<br/>claim()|
XDEL|RStream.<br/>remove()<br/>removeAsync()|RStreamReactive.<br/>remove()|RStreamRx.<br/>remove()|
XGROUP|RStream.<br/>createGroup()<br/>removeGroup()<br/>updateGroup()<br/>createGroupAsync()<br/>removeGroupAsync()<br/>updateGroupAsync()|RStreamReactive.<br/>createGroup()<br/>removeGroup()<br/>updateGroup()|RStreamRx.<br/>createGroup()<br/>removeGroup()<br/>updateGroup()|
XINFO|RStream.<br/>getInfo()<br/>listGroups()<br/>listConsumers()<br/>getInfoAsync()<br/>listGroupsAsync()<br/>listConsumersAsync()|RStreamReactive.<br/>getInfo()<br/>listGroups()<br/>listConsumers()|RStreamRx.<br/>getInfo()<br/>listGroups()<br/>listConsumers()|
XLEN|RStream.<br/>size()<br/>sizeAsync()|RStreamReactive.<br/>size()|RStreamRx.<br/>size()|
XPENDING|RStream.<br/>listPending()<br/>listPendingAsync()|RStreamReactive.<br/>listPending()|RStreamRx.<br/>listPending()|
XRANGE|RStream.<br/>range()<br/>rangeAsync()|RStreamReactive.<br/>range()|RStreamRx.<br/>range()|
XREAD|RStream.<br/>read()<br/>readAsync()|RStreamReactive.<br/>read()|RStreamRx.<br/>read()|
XREADGROUP|RStream.<br/>readGroup()<br/>readGroupAsync()|RStreamReactive.<br/>readGroup()|RStreamRx.<br/>readGroup()|
XREVRANGE|RStream.<br/>rangeReversed()<br/>rangeReversedAsync()|RStreamReactive.<br/>rangeReversed()|RStreamRx.<br/>rangeReversed()|
XTRIM|RStream.<br/>trim()<br/>trimAsync()|RStreamReactive.<br/>trim()|RStreamRx.<br/>trim()|

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,140 @@
**1. Object name**
Name of Redisson object stored as a key in Redis or Valkey.
Example:
```java
RMap map = redisson.getMap("mymap");
map.getName(); // = mymap
```
**2. Common methods**
Each Redisson object implements [RObject](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RObject.html) and [RExpirable](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RExpirable.html) interfaces.
Below are the most commonly used methods.
```java
RObject object = ...
// Copy methods
object.copy("myNewCopy");
object.copyAndReplace("myNewCopy");
// Delete methods
object.delete();
object.unlink(); // works faster because it's executed on the database side in a different thread
// Rename methods
object.rename("myNewName");
object.renamenx("myNewName"); // rename only if the new key doesn't exist
// Dump and restore methods
byte[] state = object.dump();
object.restore(state);
```
**3. Listeners per Redisson object instance**
Listeners can be attached per Redisson object instance. Base listeners are `ExpiredObjectListener` and `DeletedObjectListener`. Redisson objects may support specific listeners. Like [RScoredSortedSet](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RScoredSortedSet.html#addListener(org.redisson.api.ObjectListener)), [RStream](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RStream.html#addListener(org.redisson.api.ObjectListener)) and others.
```java
RObject object = ...
// listening to expired events
object.addListener((ExpiredObjectListener) name -> {
//...
});
// listening to delete events
object.addListener((DeletedObjectListener) name -> {
//...
});
```
**4. Operations over all Redisson object instances**
Operations over all objects are exposed by [RKeys](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RKeys.html) interface.
Usage example:
```java
RKeys keys = redisson.getKeys();
// Keys iteration
Iterable<String> allKeys = keys.getKeys();
Iterable<String> foundedKeys = keys.getKeys(KeysScanOptions.defaults().pattern("key*"));
String randomKey = keys.randomKey();
long keysAmount = keys.count();
long keysAmount = keys.countExists("obj1", "obj2", "obj3"); // amount of existing keys
// Delete methods
long delKeys = keys.delete("obj1", "obj2", "obj3");
long delKeys = keys.deleteByPattern("test?");
long delKeys = keys.unlink("obj1", "obj2", "obj3"); // works faster because it's executed on the database side in a different thread
long delKeys = keys.unlinkByPattern("test?"); // works faster because it's executed on the database side in a different thread
keys.flushall(); // Delete all keys of all existing databases
keys.flushallParallel(); // Delete all keys of all existing databases in background without blocking server
keys.flushdb(); // Delete all keys of currently selected database
```
**5. Global listeners**
Global listeners are attached to all Redisson object instances.
Available listeners:
- [TrackingListener](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/listener/TrackingListener.html),
- [SetObjectListener](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/listener/SetObjectListener.html),
- [NewObjectListener](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/listener/NewObjectListener.html),
- [ExpiredObjectListener](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/ExpiredObjectListener.html),
- [DeletedObjectListener](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/DeletedObjectListener.html),
- [FlushListener](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/listener/FlushListener.html)
Usage example:
```java
RKeys keys = redisson.getKeys();
int id = keys.addListener((NewObjectListener) name -> {
//...
});
int id = keys.addListener((DeletedObjectListener) name -> {
//...
});
int id = keys.addListener((FlushListener) address -> {
//...
});
keys.removeListener(id);
```

@ -0,0 +1,167 @@
## Id generator
Redis or Valkey based Java Id generator [RIdGenerator](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RIdGenerator.html) generates unique numbers but not monotonically increased. At first request, batch of id numbers is allocated and cached on Java side till it's exhausted. This approach allows to generate ids faster than [RAtomicLong](#atomiclong).
Default allocation size is 5000.
Default start value is 0.
Code example:
```java
RIdGenerator generator = redisson.getIdGenerator("generator");
// Initialize with start value = 12 and allocation size = 20000
generator.tryInit(12, 20000);
long id = generator.nextId();
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RIdGeneratorAsync.html) interface** usage:
```java
RIdGenerator generator = redisson.getIdGenerator("generator");
// Initialize with start value = 12 and allocation size = 20000
RFuture<Boolean> initFuture = generator.tryInitAsync(12, 20000);
RFuture<Long> idFuture = generator.nextIdAsync();
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RIdGeneratorReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RIdGenerator generator = redisson.getIdGenerator("generator");
// Initialize with start value = 12 and allocation size = 20000
Mono<Boolean> initMono = generator.tryInit(12, 20000);
Mono<Long> idMono = generator.nextId();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RIdGeneratorRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RIdGenerator generator = redisson.getIdGenerator("generator");
// Initialize with start value = 12 and allocation size = 20000
Single<Boolean> initRx = generator.tryInit(12, 20000);
Single<Long> idRx = generator.nextId();
```
## AtomicLong
Java implementation of Redis or Valkey based [AtomicLong](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicLong.html) object provides API similar to [java.util.concurrent.atomic.AtomicLong](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicLong.html) object.
Code example:
```java
RAtomicLong atomicLong = redisson.getAtomicLong("myAtomicLong");
atomicLong.set(3);
atomicLong.incrementAndGet();
atomicLong.get();
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicLongAsync.html) interface** usage:
```java
RAtomicLongAsync atomicLong = redisson.getAtomicLong("myAtomicLong");
RFuture<Void> setFuture = atomicLong.setAsync(3);
RFuture<Long> igFuture = atomicLong.incrementAndGetAsync();
RFuture<Long> getFuture = atomicLong.getAsync();
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicLongReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RAtomicLongReactive atomicLong = redisson.getAtomicLong("myAtomicLong");
Mono<Void> setMono = atomicLong.set(3);
Mono<Long> igMono = atomicLong.incrementAndGet();
RFuture<Long> getMono = atomicLong.getAsync();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicLongRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RAtomicLongRx atomicLong = redisson.getAtomicLong("myAtomicLong");
Completable setMono = atomicLong.set(3);
Single<Long> igMono = atomicLong.incrementAndGet();
Single<Long> getMono = atomicLong.getAsync();
```
## AtomicDouble
Java implementation of Redis or Valkey based [AtomicDouble](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicDouble.html) object.
Code example:
```java
RAtomicDouble atomicDouble = redisson.getAtomicDouble("myAtomicDouble");
atomicDouble.set(2.81);
atomicDouble.addAndGet(4.11);
atomicDouble.get();
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicDoubleAsync.html) interface** usage:
```java
RAtomicDoubleAsync atomicDouble = redisson.getAtomicDouble("myAtomicDouble");
RFuture<Void> setFuture = atomicDouble.setAsync(2.81);
RFuture<Double> agFuture = atomicDouble.addAndGetAsync(4.11);
RFuture<Double> getFuture = atomicDouble.getAsync();
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicDoubleReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RAtomicDoubleReactive atomicDouble = redisson.getAtomicDouble("myAtomicDouble");
Mono<Void> setMono = atomicDouble.set(2.81);
Mono<Double> agMono = atomicDouble.addAndGet(4.11);
Mono<Double> getMono = atomicDouble.get();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RAtomicDoubleRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RAtomicDoubleRx atomicDouble = redisson.getAtomicDouble("myAtomicDouble");
Completable setMono = atomicDouble.set(2.81);
Single<Double> igMono = atomicDouble.addAndGet(4.11);
Single<Double> getMono = atomicDouble.get();
```
## LongAdder
Java implementation of Redis or Valkey based [LongAdder](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLongAdder.html) object provides API similar to [java.util.concurrent.atomic.LongAdder](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/LongAdder.html) object.
It maintains internal LongAdder object on client side and provides superior performance for both increment and decrement operations. Up to __12000x__ faster than similar `AtomicLong` object. Suitable for distributed metric objects.
Code example:
```java
RLongAdder atomicLong = redisson.getLongAdder("myLongAdder");
atomicLong.add(12);
atomicLong.increment();
atomicLong.decrement();
atomicLong.sum();
```
Object should be destroyed if it's not used anymore, but it's not necessary to call destroy method if Redisson goes shutdown.
```java
RLongAdder atomicLong = ...
atomicLong.destroy();
```
## DoubleAdder
Java implementation of Redis or Valkey based [DoubleAdder](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RDoubleAdder.html) object provides API similar to [java.util.concurrent.atomic.DoubleAdder](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/DoubleAdder.html) object.
It maintains internal DoubleAdder object on client side and provides superior performance for both increment and decrement operations. Up to __12000x__ faster than similar `AtomicDouble` object. Suitable for distributed metric objects.
Code example:
```java
RLongDouble atomicDouble = redisson.getLongDouble("myLongDouble");
atomicDouble.add(12);
atomicDouble.increment();
atomicDouble.decrement();
atomicDouble.sum();
```
Object should be destroyed if it's not used anymore, but it's not necessary to call destroy method if Redisson goes shutdown.
```java
RLongDouble atomicDouble = ...
atomicDouble.destroy();
```

@ -0,0 +1,22 @@
All Redisson Java objects are Redis or Valkey cluster compatible, but their state isn't scaled/partitioned to multiple master nodes in cluster. [Redisson PRO](https://redisson.pro/) offers data partitioning for some of them. This feature offers several advantages:
1. State of single Redisson object evenly distributed across master nodes instead of single master node. This allows to avoid Redis or Valkey OutOfMemory problem.
2. Scaling read/write operations to all master nodes.
Redisson splits data to **231 partitions by default**. Minimal number of partition is **3**. Partitions are uniformly distributed across all cluster nodes. This means that each node contains nearly equal amount of partitions. For default partitions amount (231) and 4 master nodes in cluster, each node contains nearly 57 data partitions. 46 data partitions per node for 5 master nodes cluster and so on. This feature achieved thanks to special slot distribution algorithm used in Redisson.
Data partitioning supported for [Set](collections.md/#set), [Map](collections.md/#map), [BitSet](objects.md/#bitset), [Bloom filter](objects.md/#bloom-filter), [Spring Cache](../integration-with-spring.md/#spring-cache), [Hibernate Cache](../cache-api-implementations.md/#hibernate-cache), [JCache](../cache-api-implementations.md/#jcache-api-jsr-107), [Quarkus Cache](../cache-api-implementations.md/#quarkus-cache) and [Micronaut Cache](../cache-api-implementations.md/#micronaut-cache) structures.
**Joined Redis deployments**
Multiple Redis deployments could be joined and used as a single partitioned (sharded) Redis deployment.
```java
RedissonClient redisson1 = ...;
RedissonClient redisson2 = ...;
RedissonClient redisson3 = ...;
RedissonClient redisson = ShardedRedisson.create(redisson1, redisson2, redisson3);
```
_This feature available only in [Redisson PRO](https://redisson.pro) edition._

@ -0,0 +1,23 @@
Data serialization is extensively used by Redisson to marshall and unmarshall bytes received or sent over network link with Redis or Valkey server. Many popular codecs are available for usage:
Codec class name| Description
--- | ---
`org.redisson.codec.Kryo5Codec`| [Kryo 5](https://github.com/EsotericSoftware/kryo) binary codec<br/>(**Android** compatible) __Default codec__
`org.redisson.codec.KryoCodec`| [Kryo 4](https://github.com/EsotericSoftware/kryo) binary codec
`org.redisson.codec.JsonJacksonCodec`| [Jackson JSON](https://github.com/FasterXML/jackson) codec.<br/>Stores type information in `@class` field<br/>(**Android** compatible)
`org.redisson.codec.TypedJsonJacksonCodec`| Jackson JSON codec which doesn't store type id (`@class` field)
`org.redisson.codec.AvroJacksonCodec`| [Avro](http://avro.apache.org/) binary json codec
`org.redisson.codec.ProtobufCodec`| [Protobuf](https://github.com/protocolbuffers/protobuf) codec
`org.redisson.codec.FuryCodec`| [Apache Fury](https://github.com/apache/fury) codec
`org.redisson.codec.SmileJacksonCodec`| [Smile](http://wiki.fasterxml.com/SmileFormatSpec) binary json codec
`org.redisson.codec.CborJacksonCodec`| [CBOR](http://cbor.io/) binary json codec
`org.redisson.codec.MsgPackJacksonCodec`| [MsgPack](http://msgpack.org/) binary json codec
`org.redisson.codec.IonJacksonCodec`| [Amazon Ion](https://amzn.github.io/ion-docs/) codec
`org.redisson.codec.SerializationCodec`| JDK Serialization binary codec<br/>(**Android** compatible)
`org.redisson.codec.LZ4Codec`| [LZ4](https://github.com/jpountz/lz4-java) compression codec.<br/> Uses `Kryo5Codec` for serialization by default
`org.redisson.codec.LZ4CodecV2`| [LZ4 Apache Commons](https://github.com/apache/commons-compress) compression codec.<br/> Uses `Kryo5Codec` for serialization by default
`org.redisson.codec.SnappyCodecV2` | Snappy compression codec based on [snappy-java](https://github.com/xerial/snappy-java) project.<br/> Uses `Kryo5Codec` for serialization by default
`org.redisson.client.codec.StringCodec`| String codec
`org.redisson.client.codec.LongCodec`| Long codec
`org.redisson.client.codec.ByteArrayCodec` | Byte array codec
`org.redisson.codec.CompositeCodec` | Allows to mix different codecs as one

@ -0,0 +1,946 @@
## Lock
Redis or Valkey based distributed reentrant [Lock](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLock.html) object for Java and implements [Lock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html) interface. Uses pub/sub channel to notify other threads across all Redisson instances waiting to acquire a lock.
If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through [Config.lockWatchdogTimeout](../configuration.md) setting.
`leaseTime` parameter during lock acquisition can be defined. After specified time interval locked lock will be released automatically.
`RLock` object behaves according to the Java Lock specification. It means only lock owner thread can unlock it otherwise `IllegalMonitorStateException` would be thrown. Otherwise consider to use [RSemaphore](#semaphore) object.
Code example:
```java
RLock lock = redisson.getLock("myLock");
// traditional lock method
lock.lock();
// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockAsync.html) interface** usage:
```java
RLock lock = redisson.getLock("myLock");
long threadId = Thread.currentThread().getId();
RFuture<Void> lockFuture = lock.lockAsync(threadId);
// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS, threadId);
lockFuture.whenComplete((res, exception) -> {
// ...
lock.unlockAsync(threadId);
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RLockReactive lock = redisson.getLock("myLock");
long threadId = Thread.currentThread().getId();
Mono<Void> lockMono = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockMono.doOnSuccess(res -> {
// ...
})
.doFinally(r -> lock.unlock(threadId).subscribe())
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RLockRx lock = redisson.getLock("myLock");
long threadId = Thread.currentThread().getId();
Completable lockRes = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Completable lockRes = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Boolean> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockRes.doOnSuccess(res -> {
// ...
})
.doFinally(() -> lock.unlock(threadId).subscribe())
.subscribe();
```
## Fair Lock
Redis or Valkey based distributed reentrant fair [Lock](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLock.html) object for Java implements [Lock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html) interface.
Fair lock guarantees that threads will acquire it in is same order they requested it. All waiting threads are queued and if some thread has died then Redisson waits its return for 5 seconds. For example, if 5 threads are died for some reason then delay will be 25 seconds.
If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through [Config.lockWatchdogTimeout](../configuration.md) setting.
`leaseTime` parameter during lock acquisition can be defined. After specified time interval locked lock will be released automatically.
`RLock` object behaves according to the Java Lock specification. It means only lock owner thread can unlock it otherwise `IllegalMonitorStateException` would be thrown. Otherwise consider to use [RSemaphore](#semaphore) object.
Code example:
```java
RLock lock = redisson.getFairLock("myLock");
// traditional lock method
lock.lock();
// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockAsync.html) interface** usage:
```java
RLock lock = redisson.getFairLock("myLock");
RFuture<Void> lockFuture = lock.lockAsync();
// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);
lockFuture.whenComplete((res, exception) -> {
// ...
lock.unlockAsync();
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RLockReactive lock = redisson.getFairLock("myLock");
long threadId = Thread.currentThread().getId();
Mono<Void> lockMono = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockMono.doOnSuccess(res -> {
// ...
})
.doFinally(r -> lock.unlock(threadId).subscribe())
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RLockRx lock = redisson.getFairLock("myLock");
long threadId = Thread.currentThread().getId();
Completable lockRes = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Completable lockRes = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Boolean> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockRes.doOnSuccess(res -> {
// ...
})
.doFinally(() -> lock.unlock(threadId).subscribe())
.subscribe();
```
## MultiLock
Redis or Valkey based distributed `MultiLock` object allows to group [Lock](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLock.html) objects and handle them as a single lock. Each `RLock` object may belong to different Redisson instances.
If Redisson instance which acquired `MultiLock` crashes then such `MultiLock` could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through [Config.lockWatchdogTimeout](../configuration.md) setting.
`leaseTime` parameter during lock acquisition can be defined. After specified time interval locked lock will be released automatically.
`MultiLock` object behaves according to the Java Lock specification. It means only lock owner thread can unlock it otherwise `IllegalMonitorStateException` would be thrown. Otherwise consider to use [RSemaphore](#semaphore) object.
Code example:
```java
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");
RLock multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);
// traditional lock method
multiLock.lock();
// or acquire lock and automatically unlock it after 10 seconds
multiLock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = multiLock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
multiLock.unlock();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockAsync.html) interface** usage:
```java
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");
RLock multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);
long threadId = Thread.currentThread().getId();
RFuture<Void> lockFuture = multiLock.lockAsync(threadId);
// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = multiLock.lockAsync(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = multiLock.tryLockAsync(100, 10, TimeUnit.SECONDS, threadId);
lockFuture.whenComplete((res, exception) -> {
// ...
multiLock.unlockAsync(threadId);
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockReactive.html) interface** usage:
```java
RedissonReactiveClient anyRedisson = redissonClient.reactive();
RLockReactive lock1 = redisson1.getLock("lock1");
RLockReactive lock2 = redisson2.getLock("lock2");
RLockReactive lock3 = redisson3.getLock("lock3");
RLockReactive multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);
long threadId = Thread.currentThread().getId();
Mono<Void> lockMono = multiLock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = multiLock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = multiLock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockMono.doOnSuccess(res -> {
// ...
})
.doFinally(r -> multiLock.unlock(threadId).subscribe())
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockRx.html) interface** usage:
```java
RedissonRxClient anyRedisson = redissonClient.rxJava();
RLockRx lock1 = redisson1.getLock("lock1");
RLockRx lock2 = redisson2.getLock("lock2");
RLockRx lock3 = redisson3.getLock("lock3");
RLockRx multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);
long threadId = Thread.currentThread().getId();
Completable lockRes = multiLock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Completable lockRes = multiLock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Boolean> lockRes = multiLock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockRes.doOnSuccess(res -> {
// ...
})
.doFinally(() -> multiLock.unlock(threadId).subscribe())
.subscribe();
```
## RedLock
_This object is deprecated. Use [RLock](#81-lock) or [RFencedLock](#810-fenced-lock) instead._
## ReadWriteLock
Redis or Valkey based distributed reentrant [ReadWriteLock](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RReadWriteLock.html) object for Java implements [ReadWriteLock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReadWriteLock.html) interface. Both Read and Write locks implement [RLock](#lock) interface.
Multiple ReadLock owners and only one WriteLock owner are allowed.
If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through [Config.lockWatchdogTimeout](../configuration.md) setting.
Also Redisson allow to specify `leaseTime` parameter during lock acquisition. After specified time interval locked lock will be released automatically.
`RLock` object behaves according to the Java Lock specification. It means only lock owner thread can unlock it otherwise `IllegalMonitorStateException` would be thrown. Otherwise consider to use [RSemaphore](#semaphore) object.
Code example:
```java
RReadWriteLock rwlock = redisson.getReadWriteLock("myLock");
RLock lock = rwlock.readLock();
// or
RLock lock = rwlock.writeLock();
// traditional lock method
lock.lock();
// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockAsync.html) interface** usage:
```java
RReadWriteLock rwlock = redisson.getReadWriteLock("myLock");
long threadId = Thread.currentThread().getId();
RLock lock = rwlock.readLock();
// or
RLock lock = rwlock.writeLock();
RFuture<Void> lockFuture = lock.lockAsync(threadId);
// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS, threadId);
lockFuture.whenComplete((res, exception) -> {
// ...
lock.unlockAsync(threadId);
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RReadWriteLockReactive rwlock = redisson.getReadWriteLock("myLock");
RLockReactive lock = rwlock.readLock();
// or
RLockReactive lock = rwlock.writeLock();
long threadId = Thread.currentThread().getId();
Mono<Void> lockMono = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockMono.doOnSuccess(res -> {
// ...
})
.doFinally(r -> lock.unlock(threadId).subscribe())
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RReadWriteLockRx rwlock = redisson.getReadWriteLock("myLock");
RLockRx lock = rwlock.readLock();
// or
RLockRx lock = rwlock.writeLock();
long threadId = Thread.currentThread().getId();
Completable lockRes = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Completable lockRes = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Boolean> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockRes.doOnSuccess(res -> {
// ...
})
.doFinally(() -> lock.unlock(threadId).subscribe())
.subscribe();
```
## Semaphore
Redis or Valkey based distributed [Semaphore](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RSemaphore.html) object for Java similar to [Semaphore](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Semaphore.html) object.
Could be initialized before usage, but it's not requirement, with available permits amount through `trySetPermits(permits)` method.
Code example:
```java
RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
// acquire single permit
semaphore.acquire();
// or acquire 10 permits
semaphore.acquire(10);
// or try to acquire permit
boolean res = semaphore.tryAcquire();
// or try to acquire permit or wait up to 15 seconds
boolean res = semaphore.tryAcquire(15, TimeUnit.SECONDS);
// or try to acquire 10 permit
boolean res = semaphore.tryAcquire(10);
// or try to acquire 10 permits or wait up to 15 seconds
boolean res = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
semaphore.release();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RSemaphoreAsync.html) interface** usage:
```java
RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
// acquire single permit
RFuture<Void> acquireFuture = semaphore.acquireAsync();
// or acquire 10 permits
RFuture<Void> acquireFuture = semaphore.acquireAsync(10);
// or try to acquire permit
RFuture<Boolean> acquireFuture = semaphore.tryAcquireAsync();
// or try to acquire permit or wait up to 15 seconds
RFuture<Boolean> acquireFuture = semaphore.tryAcquireAsync(15, TimeUnit.SECONDS);
// or try to acquire 10 permit
RFuture<Boolean> acquireFuture = semaphore.tryAcquireAsync(10);
// or try to acquire 10 permits or wait up to 15 seconds
RFuture<Boolean> acquireFuture = semaphore.tryAcquireAsync(10, 15, TimeUnit.SECONDS);
acquireFuture.whenComplete((res, exception) -> {
// ...
semaphore.releaseAsync();
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RSemaphoreReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RSemaphoreReactive semaphore = redisson.getSemaphore("mySemaphore");
// acquire single permit
Mono<Void> acquireMono = semaphore.acquire();
// or acquire 10 permits
Mono<Void> acquireMono = semaphore.acquire(10);
// or try to acquire permit
Mono<Boolean> acquireMono = semaphore.tryAcquire();
// or try to acquire permit or wait up to 15 seconds
Mono<Boolean> acquireMono = semaphore.tryAcquire(15, TimeUnit.SECONDS);
// or try to acquire 10 permit
Mono<Boolean> acquireMono = semaphore.tryAcquire(10);
// or try to acquire 10 permits or wait up to 15 seconds
Mono<Boolean> acquireMono = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
acquireMono.doOnSuccess(res -> {
// ...
})
.doFinally(r -> semaphore.release().subscribe())
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RSemaphoreRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RSemaphoreRx semaphore = redisson.getSemaphore("mySemaphore");
// acquire single permit
Completable acquireRx = semaphore.acquire();
// or acquire 10 permits
Completable acquireRx = semaphore.acquire(10);
// or try to acquire permit
Single<Boolean> acquireRx = semaphore.tryAcquire();
// or try to acquire permit or wait up to 15 seconds
Single<Boolean> acquireRx = semaphore.tryAcquire(15, TimeUnit.SECONDS);
// or try to acquire 10 permit
Single<Boolean> acquireRx = semaphore.tryAcquire(10);
// or try to acquire 10 permits or wait up to 15 seconds
Single<Boolean> acquireRx = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
acquireRx.doOnSuccess(res -> {
// ...
})
.doFinally(() -> semaphore.release().subscribe())
.subscribe();
```
## PermitExpirableSemaphore
Redis or Valkey based distributed [Semaphore](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPermitExpirableSemaphore.html) object for Java with lease time parameter support for each acquired permit. Each permit identified by own id and could be released only using its id.
Should be initialized before usage with available permits amount through `trySetPermits(permits)` method. Allows to increase/decrease number of available permits through `addPermits(permits)` method.
Code example:
```java
RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
semaphore.trySetPermits(23);
// acquire permit
String id = semaphore.acquire();
// or acquire permit with lease time in 10 seconds
String id = semaphore.acquire(10, TimeUnit.SECONDS);
// or try to acquire permit
String id = semaphore.tryAcquire();
// or try to acquire permit or wait up to 15 seconds
String id = semaphore.tryAcquire(15, TimeUnit.SECONDS);
// or try to acquire permit with least time 15 seconds or wait up to 10 seconds
String id = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
if (id != null) {
try {
...
} finally {
semaphore.release(id);
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPermitExpirableSemaphoreAsync.html) interface** usage:
```java
RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
RFuture<Boolean> setFuture = semaphore.trySetPermitsAsync(23);
// acquire permit
RFuture<String> acquireFuture = semaphore.acquireAsync();
// or acquire permit with lease time in 10 seconds
RFuture<String> acquireFuture = semaphore.acquireAsync(10, TimeUnit.SECONDS);
// or try to acquire permit
RFuture<String> acquireFuture = semaphore.tryAcquireAsync();
// or try to acquire permit or wait up to 15 seconds
RFuture<String> acquireFuture = semaphore.tryAcquireAsync(15, TimeUnit.SECONDS);
// or try to acquire permit with least time 15 seconds or wait up to 10 seconds
RFuture<String> acquireFuture = semaphore.tryAcquireAsync(10, 15, TimeUnit.SECONDS);
acquireFuture.whenComplete((id, exception) -> {
// ...
semaphore.releaseAsync(id);
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPermitExpirableSemaphoreReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RPermitExpirableSemaphoreReactive semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
Mono<Boolean> setMono = semaphore.trySetPermits(23);
// acquire permit
Mono<String> acquireMono = semaphore.acquire();
// or acquire permit with lease time in 10 seconds
Mono<String> acquireMono = semaphore.acquire(10, TimeUnit.SECONDS);
// or try to acquire permit
Mono<String> acquireMono = semaphore.tryAcquire();
// or try to acquire permit or wait up to 15 seconds
Mono<String> acquireMono = semaphore.tryAcquire(15, TimeUnit.SECONDS);
// or try to acquire permit with least time 15 seconds or wait up to 10 seconds
Mono<String> acquireMono = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
acquireMono.flatMap(id -> {
// ...
return semaphore.release(id);
}).subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPermitExpirableSemaphoreRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RPermitExpirableSemaphoreRx semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
Single<Boolean> setRx = semaphore.trySetPermits(23);
// acquire permit
Single<String> acquireRx = semaphore.acquire();
// or acquire permit with lease time in 10 seconds
Single<String> acquireRx = semaphore.acquire(10, TimeUnit.SECONDS);
// or try to acquire permit
Maybe<String> acquireRx = semaphore.tryAcquire();
// or try to acquire permit or wait up to 15 seconds
Maybe<String> acquireRx = semaphore.tryAcquire(15, TimeUnit.SECONDS);
// or try to acquire permit with least time 15 seconds or wait up to 10 seconds
Maybe<String> acquireRx = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
acquireRx.flatMap(id -> {
// ...
return semaphore.release(id);
}).subscribe();
```
## CountDownLatch
Redis or Valkey based distributed [CountDownLatch](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RCountDownLatch.html) object for Java has structure similar to [CountDownLatch](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html) object.
Should be initialized with count by `trySetCount(count)` method before usage.
Code example:
```java
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");
latch.trySetCount(1);
// await for count down
latch.await();
// in other thread or JVM
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");
latch.countDown();
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RCountDownLatchAsync.html) interface** usage:
```java
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");
RFuture<Boolean> setFuture = lock.trySetCountAsync(1);
// await for count down
RFuture<Void> awaitFuture = latch.awaitAsync();
// in other thread or JVM
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");
RFuture<Void> countFuture = latch.countDownAsync();
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RCountDownLatchReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RCountDownLatchReactive latch = redisson.getCountDownLatch("myCountDownLatch");
Mono<Boolean> setMono = latch.trySetCount(1);
// await for count down
Mono<Void> awaitMono = latch.await();
// in other thread or JVM
RCountDownLatchReactive latch = redisson.getCountDownLatch("myCountDownLatch");
Mono<Void> countMono = latch.countDown();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RCountDownLatchRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RCountDownLatchRx latch = redisson.getCountDownLatch("myCountDownLatch");
Single<Boolean> setRx = latch.trySetCount(1);
// await for count down
Completable awaitRx = latch.await();
// in other thread or JVM
RCountDownLatchRx latch = redisson.getCountDownLatch("myCountDownLatch");
Completable countRx = latch.countDown();
```
## Spin Lock
Redis or Valkey based distributed reentrant [SpinLock](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLock.html) object for Java and implements [Lock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html) interface.
Thousands or more locks acquired/released per short time interval may cause reaching of network throughput limit and Redis or Valkey CPU overload because of pubsub usage in [Lock](#lock) object. This occurs due to nature of pubsub - messages are distributed to all nodes in cluster. Spin Lock uses Exponential Backoff strategy by default for lock acquisition instead of pubsub channel.
If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through [Config.lockWatchdogTimeout](../configuration.md) setting.
`leaseTime` parameter during lock acquisition can be defined. After specified time interval locked lock will be released automatically.
`RLock` object behaves according to the Java Lock specification. It means only lock owner thread can unlock it otherwise `IllegalMonitorStateException` would be thrown. Otherwise consider to use [RSemaphore](#semaphore) object.
Code example:
```java
RLock lock = redisson.getSpinLock("myLock");
// traditional lock method
lock.lock();
// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockAsync.html) interface** usage:
```java
RLock lock = redisson.getSpinLock("myLock");
long threadId = Thread.currentThread().getId();
RFuture<Void> lockFuture = lock.lockAsync(threadId);
// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS, threadId);
lockFuture.whenComplete((res, exception) -> {
// ...
lock.unlockAsync(threadId);
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RLockReactive lock = redisson.getSpinLock("myLock");
long threadId = Thread.currentThread().getId();
Mono<Void> lockMono = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockMono.doOnSuccess(res -> {
// ...
})
.doFinally(r -> lock.unlock(threadId).subscribe())
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RLockRx lock = redisson.getSpinLock("myLock");
long threadId = Thread.currentThread().getId();
Completable lockRes = lock.lock(threadId);
// or acquire lock and automatically unlock it after 10 seconds
Completable lockRes = lock.lock(10, TimeUnit.SECONDS, threadId);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Boolean> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS, threadId);
lockRes.doOnSuccess(res -> {
// ...
})
.doFinally(() -> lock.unlock(threadId).subscribe())
.subscribe();
```
## Fenced Lock
Redis or Valkey based distributed reentrant [FencedLock](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RFencedLock.html) object for Java and implements [Lock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html) interface.
This type of lock maintains the fencing token to avoid cases when Client acquired the lock was delayed due to long GC pause or other reason and can't detect that it doesn't own the lock anymore. To resolve this issue token is returned by locking methods or `getToken()` method. Token should be checked if it's greater or equal with the previous one by the service guarded by this lock and reject operation if condition is false.
If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through [Config.lockWatchdogTimeout](../configuration.md) setting.
`leaseTime` parameter during lock acquisition can be defined. After specified time interval locked lock will be released automatically.
`RLock` object behaves according to the Java Lock specification. It means only lock owner thread can unlock it otherwise `IllegalMonitorStateException` would be thrown. Otherwise consider to use [RSemaphore](#semaphore) object.
Code example:
```java
RFencedLock lock = redisson.getFencedLock("myLock");
// traditional lock method
Long token = lock.lockAndGetToken();
// or acquire lock and automatically unlock it after 10 seconds
token = lock.lockAndGetToken(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Long token = lock.tryLockAndGetToken(100, 10, TimeUnit.SECONDS);
if (token != null) {
try {
// check if token >= old token
...
} finally {
lock.unlock();
}
}
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockAsync.html) interface** usage:
```java
RFencedLock lock = redisson.getFencedLock("myLock");
RFuture<Long> lockFuture = lock.lockAndGetTokenAsync();
// or acquire lock and automatically unlock it after 10 seconds
RFuture<Long> lockFuture = lock.lockAndGetTokenAsync(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Long> lockFuture = lock.tryLockAndGetTokenAsync(100, 10, TimeUnit.SECONDS);
long threadId = Thread.currentThread().getId();
lockFuture.whenComplete((token, exception) -> {
if (token != null) {
try {
// check if token >= old token
...
} finally {
lock.unlockAsync(threadId);
}
}
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RFencedLockReactive lock = redisson.getFencedLock("myLock");
long threadId = Thread.currentThread().getId();
Mono<Long> lockMono = lock.lockAndGetToken();
// or acquire lock and automatically unlock it after 10 seconds
Mono<Long> lockMono = lock.lockAndGetToken(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Long> lockMono = lock.tryLockAndGetToken(100, 10, TimeUnit.SECONDS);
lockMono.doOnSuccess(token -> {
if (token != null) {
try {
// check if token >= old token
...
} finally {
lock.unlock(threadId).subscribe();
}
}
})
.subscribe();
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RLockRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RFencedLockRx lock = redisson.getFencedLock("myLock");
Single<Long> lockRes = lock.lockAndGetToken();
// or acquire lock and automatically unlock it after 10 seconds
Single<Long> lockRes = lock.lockAndGetToken(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Long> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS);
long threadId = Thread.currentThread().getId();
lockRes.doOnSuccess(token -> {
if (token != null) {
try {
// check if token >= old token
...
} finally {
lock.unlock(threadId).subscribe();
}
}
})
.subscribe();
```

@ -0,0 +1,16 @@
It's possible to use a Redisson object inside another Redisson object in any combination. In this case a special reference object will be used and handled by Redisson.
Usage example:
```java
RMap<RSet<RList>, RList<RMap>> map = redisson.getMap("myMap");
RSet<RList> set = redisson.getSet("mySet");
RList<RMap> list = redisson.getList("myList");
map.put(set, list);
// With the help of the special reference object, we can even create a circular
// reference which is impossible to achieve if we were to serialize its content
set.add(list);
list.add(map);
```
As you may have noticed there is no need to re "save/persist" the map object after its elements have changed. Because it does not contain any value but merely a reference, this makes Redisson objects behaves much more like standard Java objects. In effect, making Redis or Valkey becomes part of JVM's memory rather than just a simple repository.
One Redis HASH, one Redis SET and one Redis LIST will be created in the example above.

@ -0,0 +1,626 @@
## Object holder
Java implementation of Redis or Valkey based [RBucket](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucket.html) object is a holder for any type of object. Size is limited to 512Mb.
Code example:
```java
RBucket<AnyObject> bucket = redisson.getBucket("anyObject");
bucket.set(new AnyObject(1));
AnyObject obj = bucket.get();
bucket.trySet(new AnyObject(3));
bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
bucket.getAndSet(new AnyObject(6));
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketAsync.html) interface** usage:
```java
RBucket<AnyObject> bucket = redisson.getBucket("anyObject");
RFuture<Void> future = bucket.setAsync(new AnyObject(1));
RFuture<AnyObject> objfuture = bucket.getAsync();
RFuture<Boolean> tsFuture = bucket.trySetAsync(new AnyObject(3));
RFuture<Boolean> csFuture = bucket.compareAndSetAsync(new AnyObject(4), new AnyObject(5));
RFuture<AnyObject> gsFuture = bucket.getAndSetAsync(new AnyObject(6));
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RBucketReactive<AnyObject> bucket = redisson.getBucket("anyObject");
Mono<Void> mono = bucket.set(new AnyObject(1));
Mono<AnyObject> objMono = bucket.get();
Mono<Boolean> tsMono = bucket.trySet(new AnyObject(3));
Mono<Boolean> csMono = bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
Mono<AnyObject> gsMono = bucket.getAndSet(new AnyObject(6));
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RBucketRx<AnyObject> bucket = redisson.getBucket("anyObject");
Completable rx = bucket.set(new AnyObject(1));
Maybe<AnyObject> objRx = bucket.get();
Single<Boolean> tsRx = bucket.trySet(new AnyObject(3));
Single<Boolean> csRx = bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
Maybe<AnyObject> gsRx = bucket.getAndSet(new AnyObject(6));
```
<br/>
<br/>
Use [RBuckets](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBuckets.html) interface to execute operations over multiple [RBucket](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucket.html) objects:
Code example:
```java
RBuckets buckets = redisson.getBuckets();
// get all bucket values
Map<String, V> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
Map<String, Object> map = new HashMap<>();
map.put("myBucket1", new MyObject());
map.put("myBucket2", new MyObject());
// sets all or nothing if some bucket is already exists
buckets.trySet(map);
// store all at once
buckets.set(map);
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketsAsync.html) interface** usage:
```java
RBuckets buckets = redisson.getBuckets();
// get all bucket values
RFuture<Map<String, V>> bucketsFuture = buckets.getAsync("myBucket1", "myBucket2", "myBucket3");
Map<String, Object> map = new HashMap<>();
map.put("myBucket1", new MyObject());
map.put("myBucket2", new MyObject());
// sets all or nothing if some bucket is already exists
RFuture<Boolean> tsFuture = buckets.trySetAsync(map);
// store all at once
RFuture<Void> sFuture = buckets.setAsync(map);
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketsReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RBucketsReactive buckets = redisson.getBuckets();
// get all bucket values
Mono<Map<String, V>> bucketsMono = buckets.getAsync("myBucket1", "myBucket2", "myBucket3");
Map<String, Object> map = new HashMap<>();
map.put("myBucket1", new MyObject());
map.put("myBucket2", new MyObject());
// sets all or nothing if some bucket is already exists
Mono<Boolean> tsMono = buckets.trySet(map);
// store all at once
Mono<Void> sMono = buckets.set(map);
```
Code example of **[RxJava](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketsRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RBucketsRx buckets = redisson.getBuckets();
// get all bucket values
Single<Map<String, V>> bucketsRx = buckets.get("myBucket1", "myBucket2", "myBucket3");
Map<String, Object> map = new HashMap<>();
map.put("myBucket1", new MyObject());
map.put("myBucket2", new MyObject());
// sets all or nothing if some bucket is already exists
Single<Boolean> tsRx = buckets.trySet(map);
// store all at once
Completable sRx = buckets.set(map);
```
### Listeners
Redisson allows to bind listeners per `RBucket` object.
|Listener class name|Event description |
|:--:|:--:|
|org.redisson.api.listener.TrackingListener|Data created/updated after read operation|
|org.redisson.api.listener.SetObjectListener|Data created/updated|
|org.redisson.api.ExpiredObjectListener|`RBucket` object expired|
|org.redisson.api.DeletedObjectListener|`RBucket` object deleted|
Usage example:
```java
RBucket<String> set = redisson.getBucket("anyObject");
int listenerId = set.addListener(new SetObjectListener() {
@Override
public void onSet(String name) {
// ...
}
});
int listenerId = set.addListener(new DeletedObjectListener() {
@Override
public void onDeleted(String name) {
// ...
}
});
// ...
set.removeListener(listenerId);
```
## Binary stream holder
Java implementation of Redis or Valkey based [RBinaryStream](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RBinaryStream.html) object holds sequence of bytes. It extends [RBucket](#object-holder) interface and size is limited to 512Mb.
Code example:
```java
RBinaryStream stream = redisson.getBinaryStream("anyStream");
byte[] content = ...
stream.set(content);
stream.getAndSet(content);
stream.trySet(content);
stream.compareAndSet(oldContent, content);
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBucketAsync.html) interface** usage:
```java
RBinaryStream stream = redisson.getBinaryStream("anyStream");
byte[] content = ...
RFuture<Void> future = stream.set(content);
RFuture<byte[]> future = stream.getAndSet(content);
RFuture<Boolean> future = stream.trySet(content);
RFuture<Boolean> future = stream.compareAndSet(oldContent, content);
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBinaryStreamReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RBinaryStreamReactive stream = redisson.getBinaryStream("anyStream");
ByteBuffer content = ...
Mono<Void> mono = stream.set(content);
Mono<byte[]> mono = stream.getAndSet(content);
Mono<Boolean> mono = stream.trySet(content);
Mono<Boolean> mono = stream.compareAndSet(oldContent, content);
Mono<Integer> mono = stream.write(content);
stream.position(0);
Mono<Integer> mono = stream.read(b);
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBinaryStreamRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RBinaryStreamRx stream = redisson.getBinaryStream("anyStream");
ByteBuffer content = ...
Completable rx = stream.set(content);
Maybe<byte[]> rx = stream.getAndSet(content);
Single<Boolean> rx = stream.trySet(content);
Single<Boolean> rx = stream.compareAndSet(oldContent, content);
Single<Integer> rx = stream.write(content);
stream.position(0);
Single<Integer> rx = stream.read(b);
```
Code example of [java.io.InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) and [java.io.OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html) interfaces usage:
```java
RBinaryStream stream = redisson.getBinaryStream("anyStream");
InputStream is = stream.getInputStream();
byte[] readBuffer = ...
is.read(readBuffer);
OutputStream os = stream.getOuputStream();
byte[] contentToWrite = ...
os.write(contentToWrite);
```
Code example of [java.nio.channels.SeekableByteChannel](https://docs.oracle.com/javase/8/docs/api/java/nio/channels/SeekableByteChannel.html) interface usage:
```java
RBinaryStream stream = redisson.getBinaryStream("anyStream");
SeekableByteChannel sbc = stream.getChannel();
ByteBuffer readBuffer = ...
sbc.read(readBuffer);
sbc.position(0);
ByteBuffer contentToWrite = ...
sbc.write(contentToWrite);
sbc.truncate(234);
```
Code example of [java.nio.channels.AsynchronousByteChannel](https://docs.oracle.com/javase/8/docs/api/java/nio/channels/AsynchronousByteChannel.html) interface usage:
```java
RBinaryStream stream = redisson.getBinaryStream("anyStream");
AsynchronousByteChannel sbc = stream.getAsynchronousChannel();
ByteBuffer readBuffer = ...
sbc.read(readBuffer);
ByteBuffer contentToWrite = ...
sbc.write(contentToWrite);
```
### Listeners
Redisson allows to bind listeners per `RBinaryStream` object.
|Listener class name|Event description |
|:--:|:--:|
|org.redisson.api.listener.TrackingListener|Data created/updated after read operation|
|org.redisson.api.listener.SetObjectListener|Data created/updated|
|org.redisson.api.ExpiredObjectListener|`RBinaryStream` object expired|
|org.redisson.api.DeletedObjectListener|`RBinaryStream` object deleted|
Usage example:
```java
RBinaryStream stream = redisson.getBinaryStream("anyObject");
int listenerId = set.addListener(new DeletedObjectListener() {
@Override
public void onDeleted(String name) {
// ...
}
});
// ...
set.removeListener(listenerId);
```
## JSON object holder
Java implementation of [RJsonBucket](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RJsonBucket.html) object stores data in JSON format using `JSON.*` commands. JSON data encoding/decoding handled by `JsonCodec` which is a required parameter. Available implementation is `org.redisson.codec.JacksonCodec` which is thread-safe.
Use [JSON Store](collections.md/#json-store) for key-value implementation and local cache.
### Local cache
Redisson provides JSON object holder implementation with local cache.
**local cache** - so called near cache used to speed up read operations and avoid network roundtrips. It caches whole JSON object on Redisson side and executes read operations up to **45x faster** in comparison with common implementation. Local cache instances with the same name connected to the same pub/sub channel. This channel is used to exchange invalidate events between instances.
|RedissonClient<br/>method name | Local cache | Ultra-fast<br/>read/write |
| ------------- | :-----------: | :---------:|
|getJsonBucket()<br/><sub><i>open-source version</i></sub> | ❌ | ❌ |
|getJsonBucket()<br/><sub><i>[Redisson PRO](https://redisson.pro) version</i></sub> | ❌ | ✔️ |
|getLocalCachedJsonBucket()<br/><sub><i>[Redisson PRO](https://redisson.pro) version</i></sub> | ✔️ | ✔️ |
Code example:
```java
RJsonBucket<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
// or local cached instance
RLocalCachedJsonBucket<AnyObject> bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
bucket.set(new AnyObject(1));
AnyObject obj = bucket.get();
bucket.trySet(new AnyObject(3));
bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
bucket.getAndSet(new AnyObject(6));
List<String> values = bucket.get(new JacksonCodec<>(new TypeReference<List<String>>() {}), "values");
long aa = bucket.arrayAppend("$.obj.values", "t3", "t4");
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RJsonBucketAsync.html) interface** usage:
```java
RJsonBucket<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
// or local cached instace
RLocalCachedJsonBucket<AnyObject> bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
RFuture<Void> future = bucket.setAsync(new AnyObject(1));
RFuture<AnyObject> objfuture = bucket.getAsync();
RFuture<Boolean> tsFuture = bucket.trySetAsync(new AnyObject(3));
RFuture<Boolean> csFuture = bucket.compareAndSetAsync(new AnyObject(4), new AnyObject(5));
RFuture<AnyObject> gsFuture = bucket.getAndSetAsync(new AnyObject(6));
RFutue<List<String>> gFuture = bucket.getAsync(new JacksonCodec<>(new TypeReference<List<String>>() {}), "obj.values");
RFutue<Long> aaFuture = bucket.arrayAppendAsync("$.obj.values", "t3", "t4");
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RJsonBucketReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RJsonBucketReactive<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
// or local cached instance
RLocalCachedJsonBucketReactive<AnyObject> bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
Mono<Void> mono = bucket.set(new AnyObject(1));
Mono<AnyObject> objMono = bucket.get();
Mono<Boolean> tsMono = bucket.trySet(new AnyObject(3));
Mono<Boolean> csMono = bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
Mono<AnyObject> gsMono = bucket.getAndSet(new AnyObject(6));
Mono<List<String>> vsMono = bucket.get(new JacksonCodec<>(new TypeReference<List<String>>() {}), "values");
Mono<Long> aaMono = bucket.arrayAppend("$.obj.values", "t3", "t4");
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RJsonBucketRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RJsonBucketRx<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
// or local cached instance
RLocalCachedJsonBucketRx<AnyObject> bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class));
Completable rx = bucket.set(new AnyObject(1));
Maybe<AnyObject> objRx = bucket.get();
Single<Boolean> tsRx = bucket.trySet(new AnyObject(3));
Single<Boolean> csRx = bucket.compareAndSet(new AnyObject(4), new AnyObject(5));
Maybe<AnyObject> gsRx = bucket.getAndSet(new AnyObject(6));
Single<List<String>> valuesRx = bucket.get(new JacksonCodec<>(new TypeReference<List<String>>() {}), "values");
Single<Long> aaRx = bucket.arrayAppend("$.obj.values", "t3", "t4");
```
## Geospatial holder
Java implementation of Redis or Valkey based [RGeo](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RGeo.html) object is a holder for geospatial items.
Code example:
```java
RGeo<String> geo = redisson.getGeo("test");
geo.add(new GeoEntry(13.361389, 38.115556, "Palermo"),
new GeoEntry(15.087269, 37.502669, "Catania"));
Double distance = geo.dist("Palermo", "Catania", GeoUnit.METERS);
Map<String, GeoPosition> positions = geo.pos("test2", "Palermo", "test3", "Catania", "test1");
List<String> cities = geo.search(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
Map<String, GeoPosition> citiesWithPositions = geo.searchWithPosition(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RGeoAsync.html) interface** usage:
```java
RGeo<String> geo = redisson.getGeo("test");
RFuture<Long> addFuture = geo.addAsync(new GeoEntry(13.361389, 38.115556, "Palermo"),
new GeoEntry(15.087269, 37.502669, "Catania"));
RFuture<Double> distanceFuture = geo.distAsync("Palermo", "Catania", GeoUnit.METERS);
RFuture<Map<String, GeoPosition>> positionsFuture = geo.posAsync("test2", "Palermo", "test3", "Catania", "test1");
RFuture<List<String>> citiesFuture = geo.searchAsync(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
RFuture<Map<String, GeoPosition>> citiesWithPositions = geo.searchWithPositionAsync(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RGeoReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RGeoReactive<String> bucket = redisson.getGeo("test");
Mono<Long> addFuture = geo.add(new GeoEntry(13.361389, 38.115556, "Palermo"),
new GeoEntry(15.087269, 37.502669, "Catania"));
Mono<Double> distanceFuture = geo.dist("Palermo", "Catania", GeoUnit.METERS);
Mono<Map<String, GeoPosition>> positionsFuture = geo.pos("test2", "Palermo", "test3", "Catania", "test1");
Mono<List<String>> citiesFuture = geo.search(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
Mono<Map<String, GeoPosition>> citiesWithPositions = geo.searchWithPosition(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RGeoRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RGeoRx<String> bucket = redisson.getGeo("test");
Single<Long> addFuture = geo.add(new GeoEntry(13.361389, 38.115556, "Palermo"),
new GeoEntry(15.087269, 37.502669, "Catania"));
Single<Double> distanceFuture = geo.dist("Palermo", "Catania", GeoUnit.METERS);
Single<Map<String, GeoPosition>> positionsFuture = geo.pos("test2", "Palermo", "test3", "Catania", "test1");
Single<List<String>> citiesFuture = geo.search(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
Single<Map<String, GeoPosition>> citiesWithPositions = geo.searchWithPosition(GeoSearchArgs.from(15, 37).radius(200, GeoUnit.KILOMETERS));
```
## BitSet
Java implementation of Redis or Valkey based [RBitSet](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBitSet.html) object provides API similar to [java.util.BitSet](https://docs.oracle.com/javase/8/docs/api/java/util/BitSet.html). It represents vector of bits that grows as needed. Size limited to `4 294 967 295` bits.
Code example:
```java
RBitSet set = redisson.getBitSet("simpleBitset");
set.set(0, true);
set.set(1812, false);
set.clear(0);
set.and("anotherBitset");
set.xor("anotherBitset");
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBitSetAsync.html) interface** usage:
```java
RBitSetAsync set = redisson.getBitSet("simpleBitset");
RFuture<Boolean> setFuture = set.setAsync(0, true);
RFuture<Boolean> setFuture = set.setAsync(1812, false);
RFuture<Void> clearFuture = set.clearAsync(0);
RFuture<Void> andFuture = set.andAsync("anotherBitset);
RFuture<Void> xorFuture = set.xorAsync("anotherBitset");
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBitSetReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RBitSetReactive stream = redisson.getBitSet("simpleBitset");
Mono<Boolean> setMono = set.set(0, true);
Mono<Boolean> setMono = set.set(1812, false);
Mono<Void> clearMono = set.clear(0);
Mono<Void> andMono = set.and("anotherBitset);
Mono<Void> xorMono = set.xor("anotherBitset");
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBitSetRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RBitSetRx stream = redisson.getBitSet("simpleBitset");
Single<Boolean> setRx = set.set(0, true);
Single<Boolean> setRx = set.set(1812, false);
Completable clearRx = set.clear(0);
Completable andRx = set.and("anotherBitset);
Completable xorRx = set.xor("anotherBitset");
```
### Data partitioning
Although 'RBitSet' object is cluster compatible its content isn't scaled across multiple master nodes. BitSet data partitioning available only in cluster mode and implemented by separate `RClusteredBitSet` object. It uses distributed implementation of roaring bitmap structure. Size is limited by whole Cluster memory. More details about partitioning [here](data-partitioning.md).
Below is the list of all available BitSet implementations:
|RedissonClient <br/> method name | Data partitioning <br/> support | Ultra-fast read/write |
| ------------- | :----------:| :----------:|
|getBitSet()<br/><sub><i>open-source version</i></sub> | ❌ | ❌ |
|getBitSet()<br/><sub><i>[Redisson PRO](https://redisson.pro) version</i></sub> | ❌ | ✔️ |
|getClusteredBitSet()<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ✔️ | ✔️ |
Code example:
```java
RClusteredBitSet set = redisson.getClusteredBitSet("simpleBitset");
set.set(0, true);
set.set(1812, false);
set.clear(0);
set.addAsync("e");
set.xor("anotherBitset");
```
## Bloom filter
Redis or Valkey based distributed [RBloomFilter](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RBloomFilter.html) bloom filter for Java. Number of contained bits is limited to `2^32` with [data partitioning](data-partitioning.md) to `2^63`
Must be initialized with capacity size by `tryInit(expectedInsertions, falseProbability)` method before usage.
```java
RBloomFilter<SomeObject> bloomFilter = redisson.getBloomFilter("sample");
// initialize bloom filter with
// expectedInsertions = 55000000
// falseProbability = 0.03
bloomFilter.tryInit(55000000L, 0.03);
bloomFilter.add(new SomeObject("field1Value", "field2Value"));
bloomFilter.add(new SomeObject("field5Value", "field8Value"));
bloomFilter.contains(new SomeObject("field1Value", "field8Value"));
bloomFilter.count();
```
### Data partitioning
_This feature available only in [Redisson PRO](https://redisson.pro) edition._
Although 'RBloomFilter' object is cluster compatible its content isn't scaled across multiple master nodes. Bloom Filter data partitioning support available only in cluster mode and implemented by separate `RClusteredBloomFilter` object. This implementation uses more efficient distributed memory allocation algorithm. It allows to "shrink" memory space consumed by unused bits across all Redis or Valkey nodes. State of each instance is partitioned across all nodes in Redis or Valkey cluster. Number of contained bits is limited to `2^63`. More details about partitioning [here](data-partitioning.md).
Below is the list of all available BloomFilter implementations:
|RedissonClient <br/> method name | Data partitioning <br/> support | Ultra-fast read/write | Bits amount limit |
| ------------- | :----------:| :----------:| :----------:|
|getBloomFilter()<br/><sub><i>open-source version</i></sub> | ❌ | ❌ | 2^32 |
|getBloomFilter()<br/><sub><i>[Redisson PRO](https://redisson.pro) version</i></sub> | ❌ | ✔️ | 2^32 |
|getClusteredBloomFilter()<br/><sub><i>available only in [Redisson PRO](https://redisson.pro)</i></sub> | ✔️ | ✔️ | **2^63** |
```java
RClusteredBloomFilter<SomeObject> bloomFilter = redisson.getClusteredBloomFilter("sample");
// initialize bloom filter with
// expectedInsertions = 255000000
// falseProbability = 0.03
bloomFilter.tryInit(255000000L, 0.03);
bloomFilter.add(new SomeObject("field1Value", "field2Value"));
bloomFilter.add(new SomeObject("field5Value", "field8Value"));
bloomFilter.contains(new SomeObject("field1Value", "field8Value"));
```
## HyperLogLog
Redis or Valkey based distributed [RHyperLogLog](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RHyperLogLog.html) object for Java. Probabilistic data structure that lets you maintain counts of millions of items with extreme space efficiency.
It has [Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RHyperLogLogAsync.html), [Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RHyperLogLogReactive.html) and [RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RHyperLogLogRx.html) interfaces.
```java
RHyperLogLog<Integer> log = redisson.getHyperLogLog("log");
log.add(1);
log.add(2);
log.add(3);
log.count();
```
## RateLimiter
Redis or Valkey based distributed [RateLimiter](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RRateLimiter.html) object for Java restricts the total rate of calls either from all threads regardless of Redisson instance or from all threads working with the same Redisson instance. Doesn't guarantee fairness.
Code example:
```java
RRateLimiter limiter = redisson.getRateLimiter("myLimiter");
// Initialization required only once.
// 5 permits per 2 seconds
limiter.trySetRate(RateType.OVERALL, 5, 2, RateIntervalUnit.SECONDS);
// acquire 3 permits or block until they became available
limiter.acquire(3);
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RRateLimiterAsync.html) interface** usage:
```java
RRateLimiter limiter = redisson.getRateLimiter("myLimiter");
// Initialization required only once.
// 5 permits per 2 seconds
RFuture<Boolean> setRateFuture = limiter.trySetRate(RateType.OVERALL, 5, 2, RateIntervalUnit.SECONDS);
// acquire 3 permits or block until they became available
RFuture<Void> aquireFuture = limiter.acquire(3);
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RRateLimiterReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RRateLimiterReactive limiter = redisson.getRateLimiter("myLimiter");
// Initialization required only once.
// 5 permits per 2 seconds
Mono<Boolean> setRateMono = limiter.trySetRate(RateType.OVERALL, 5, 2, RateIntervalUnit.SECONDS);
// acquire 3 permits or block until they became available
Mono<Void> aquireMono = limiter.acquire(3);
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RRateLimiterRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RRateLimiterRx limiter = redisson.getRateLimiter("anyObject");
// Initialization required only once.
// 5 permits per 2 seconds
Single<Boolean> setRateRx = limiter.trySetRate(RateType.OVERALL, 5, 2, RateIntervalUnit.SECONDS);
// acquire 3 permits or block until they became available
Completable aquireRx = limiter.acquire(3);
```

@ -0,0 +1,262 @@
## Topic
Java implementation of Redis or Valkey based [RTopic](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RTopic.html) object implements Publish / Subscribe mechanism. It allows to subscribe on events published with multiple instances of `RTopic` object with the same name.
Listeners are re-subscribed automatically after reconnection or failover. All messages sent during absence of connection are lost. Use [Reliable Topic](#reliable-topic) for reliable delivery.
Code example:
```java
RTopic topic = redisson.getTopic("myTopic");
int listenerId = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RTopic topic = redisson.getTopic("myTopic");
long clientsReceivedMessage = topic.publish(new SomeObject());
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RTopicAsync.html) interface** usage:
```java
RTopicAsync topic = redisson.getTopic("myTopic");
RFuture<Integer> listenerFuture = topic.addListenerAsync(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RTopicAsync topic = redisson.getTopic("myTopic");
RFuture<Long> publishFuture = topic.publishAsync(new SomeObject());
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RTopicReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RTopicReactive topic = redisson.getTopic("myTopic");
Mono<Integer> listenerMono = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RTopicReactive topic = redisson.getTopic("myTopic");
Mono<Long> publishMono = topic.publish(new SomeObject());
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RTopicRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RTopicRx topic = redisson.getTopic("myTopic");
Single<Integer> listenerMono = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RTopicRx topic = redisson.getTopic("myTopic");
Single<Long> publishMono = topic.publish(new SomeObject());
```
## Topic pattern
Java implementation of Redis or Valkey based [RPatternTopic](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPatternTopic.html) object. It allows to subscribe to multiple topics by specified glob-style pattern.
Listeners are re-subscribed automatically after reconnection to a server or failover.
Pattern examples:
* `topic?` subscribes to `topic1`, `topicA` ...
* `topic?_my` subscribes to `topic_my`, `topic123_my`, `topicTEST_my` ...
* `topic[ae]` subscribes to `topica` and `topice` only
Code example:
```java
// subscribe to all topics by `topic*` pattern
RPatternTopic patternTopic = redisson.getPatternTopic("topic*");
int listenerId = patternTopic.addListener(Message.class, new PatternMessageListener<Message>() {
@Override
public void onMessage(String pattern, String channel, Message msg) {
//...
}
});
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPatternTopicAsync.html) interface** usage:
```java
RPatternTopicAsync patternTopic = redisson.getPatternTopic("topic*");
RFuture<Integer> listenerFuture = patternTopic.addListenerAsync(Message.class, new PatternMessageListener<Message>() {
@Override
public void onMessage(String pattern, String channel, Message msg) {
//...
}
});
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPatternTopicReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RTopicReactive patternTopic = redisson.getPatternTopic("topic*");
Mono<Integer> listenerMono = patternTopic.addListener(Message.class, new PatternMessageListener<Message>() {
@Override
public void onMessage(String pattern, String channel, Message msg) {
//...
}
});
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RPatternTopicRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RTopicRx patternTopic = redisson.getPatternTopic("topic*");
Single<Integer> listenerSingle = patternTopic.addListener(Message.class, new PatternMessageListener<Message>() {
@Override
public void onMessage(String pattern, String channel, Message msg) {
//...
}
});
```
## Sharded topic
Java implementation of Redis or Valkey based [RShardedTopic](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RShardedTopic.html) object implements Sharded Publish / Subscribe mechanism. It allows to subscribe on events published with multiple instances of `RShardedTopic` object with the same name. Subscribe/publish operations are executed only on Redis or Valkey node in Cluster which is bounded to specific topic name. Published messages via `RShardedTopic` aren't broadcasted across all nodes as for `RTopic` object. Which reduces network bandwidth and Redis or Valkey load.
Listeners are re-subscribed automatically after reconnection to a server or failover. All messages sent during absence of connection are lost. Use [Reliable Topic](#reliable-topic) for reliable delivery.
Code example:
```java
RShardedTopic topic = redisson.getShardedTopic("myTopic");
int listenerId = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RShardedTopic topic = redisson.getShardedTopic("myTopic");
long clientsReceivedMessage = topic.publish(new SomeObject());
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RShardedTopicAsync.html) interface** usage:
```java
RShardedTopicAsync topic = redisson.getShardedTopic("myTopic");
RFuture<Integer> listenerFuture = topic.addListenerAsync(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RShardedTopicAsync topic = redisson.getShardedTopic("myTopic");
RFuture<Long> publishFuture = topic.publishAsync(new SomeObject());
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RShardedTopicReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RShardedTopicReactive topic = redisson.getShardedTopic("myTopic");
Mono<Integer> listenerMono = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RShardedTopicReactive topic = redisson.getShardedTopic("myTopic");
Mono<Long> publishMono = topic.publish(new SomeObject());
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RShardedTopicRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RShardedTopicRx topic = redisson.getShardedTopic("myTopic");
Single<Integer> listenerMono = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RShardedTopicRx topic = redisson.getShardedTopic("myTopic");
Single<Long> publishMono = topic.publish(new SomeObject());
```
## Reliable Topic
Java implementation of Redis or Valkey based [RReliableTopic](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RReliableTopic.html) object implements Publish / Subscribe mechanism with reliable delivery of messages. In case of Redis or Valkey connection interruption all missed messages are delivered after reconnection to Redis. Message considered as delivered when it was received by Redisson and submited for processing by topic listeners.
Each `RReliableTopic` object instance (subscriber) has own watchdog which is started when the first listener was registered. Subscriber expires after `org.redisson.config.Config#reliableTopicWatchdogTimeout` timeout if watchdog didn't extend it to the next timeout time interval. This prevents against infinity grow of stored messages in topic due to Redisson client crash or any other reason when subscriber unable to consume messages.
Topic listeners are resubscribed automatically after reconnection to a server or failover.
Code example:
```java
RReliableTopic topic = redisson.getReliableTopic("anyTopic");
topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(CharSequence channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RReliableTopic topic = redisson.getReliableTopic("anyTopic");
long subscribersReceivedMessage = topic.publish(new SomeObject());
```
Code example of **[Async](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RReliableTopicAsync.html) interface** usage:
```java
RReliableTopicAsync topic = redisson.getReliableTopic("anyTopic");
RFuture<String> listenerFuture = topic.addListenerAsync(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(CharSequence channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RReliableTopicAsync topic = redisson.getReliableTopic("anyTopic");
RFuture<Long> future = topic.publishAsync(new SomeObject());
```
Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RReliableTopicReactive.html) interface** usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RReliableTopicReactive topic = redisson.getReliableTopic("anyTopic");
Mono<String> listenerMono = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(CharSequence channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RReliableTopicReactive topic = redisson.getReliableTopic("anyTopic");
Mono<Long> publishMono = topic.publish(new SomeObject());
```
Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RReliableTopicRx.html) interface** usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RReliableTopicRx topic = redisson.getReliableTopic("anyTopic");
Single<String> listenerRx = topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(CharSequence channel, SomeObject message) {
//...
}
});
// in other thread or JVM
RReliableTopicRx topic = redisson.getReliableTopic("anyTopic");
Single<Long> publisRx = topic.publish(new SomeObject());
```

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
Below is the libraries used by Redisson:
| Group id | Artifact Id | Version | Dependency |
| ------------- | ------------- | ------------| ------------|
| com.esotericsoftware | kryo | 5.4+| **required** (if Kryo is used as codec)|
| com.esotericsoftware | reflectasm | 1.11+ | **required** (if Kryo is used as codec)|
| com.esotericsoftware | minlog | 1.3+ | **required** (if Kryo is used as codec)|
| org.objenesis | objenesis| 3.3+ | **required** (if Kryo is used as codec)|
| io.netty | netty-common | 4.1+ | **required**|
| io.netty | netty-codec | 4.1+ | **required** |
| io.netty | netty-buffer | 4.1+ | **required** |
| io.netty | netty-transport | 4.1+ | **required** |
| io.netty | netty-handler | 4.1+ | **required** |
| io.netty | netty-resolver | 4.1+ | **required** |
| io.netty | netty-resolver-dns | 4.1+ | **required** |
| com.fasterxml.jackson.dataformat | jackson-core | 2.7+ | **required** |
| com.fasterxml.jackson.dataformat | jackson-databind | 2.7+ | **required** |
| com.fasterxml.jackson.dataformat | jackson-annotations | 2.7+ | **required** |
| com.fasterxml.jackson.dataformat | jackson-dataformat-yaml | 2.7+ | **required** |
| org.yaml | snakeyaml | 1.0+ | **required** |
| net.bytebuddy | byte-buddy | 1.6+ | _optional (used by LiveObject service)_ |
| org.jodd | jodd-bean | 3.7+ | _optional (used by LiveObject service)_ |
| javax.cache | cache-api | 1.1.1 | _optional (used by JCache implementation)_ |
| io.projectreactor | reactor-core | 3.1+ | _optional (used by RedissonReactiveClient)_ |
| io.reactivex.rxjava3 | rxjava | 3.0+ | _optional (used by RedissonRxClient)_ |

@ -0,0 +1,47 @@
**Q: What is the cause of RedisTimeoutException?**
**A** : There are multiple reasons:
1. All netty threads are busy, leading to delays in both Redis response decoding and sending commands to Redis.
2. All connections are busy.
3. Redis server is busy and takes too long to respond the request.
4. Java application is busy.
5. Blocking invocation in async/reactive/rx listeners or subscribeOnElements methods.
6. Server CPU throttling. For GCP hosting try to add `--no-cpu-throttling` to CloudRun container which connects via Redisson to the Redis instance.
7. Unstable network with TCP packet drops.
8. Redis vendor limits concurrent connections amount.
First try to set follow values for `nettyThreads` setting: 32, 64, 128, 256 this allows Redisson to get a free netty thread to decode a response or send a command. Next, try to increase `retryInterval` and/or `timeout` to a reasonable value so that a command can still gracefully fail without having the end user wait forever. At the last step, try to increase `connection pool` setting so that Redisson can stand a better chance in getting a free connection.
Complex commands such as `keys`, `hmget` and big loops in Lua scripts are more likely to see it than other commands. It is important to understand an operation can still timeout despite the absence of it from the Redis slowlog. Slowlogs only record the time a command is been processed by the Redis event loop and not anything before or after. Network issue may also cause this exception when a response is still in-flight.
**Q: When do I need to shut down a Redisson instance, at the end of each request or the end of the life of a thread?**
**A** : Redisson instance requires manual shutdown only if you want to stop using all of its features. It is a common pattern that Redisson starts and stops along with the application. Since it is completely thread safe, you may treat a Redisson instance as a singleton. The shutdown sequence will disconnect all the active connections held in each connection pool, and it will clean up certain types of Redisson objects require a manual destroy action upon disposal, it will then stop the event loops. Please be advised, the entire shutdown process is not instant.
**Q: In MapCache/SetCache/SpringCache/JCache, I have set an expiry time to an entry, why is it still in Redis when it should be disappeared?**
**A** : The first and foremost thing you need to understand is entry expiry feature is not supported by Redis. This is one of Redissons own creation. Which means it requires Redisson to work. You cant expect a correct behaviour using other clients such as redis-cli or even jedis.
Redisson employs both active approach and passive approach, just like Redis server, to ensure an element is evicted when its time is due. There is are scheduled eviction tasks that runs periodically to remove the expired elements from the collection, Redisson also checks the expiry information when an element is accessed: if it has expired, it will be removed and a null value will be returned.
So if you saw the stale value in redis-cli, please do not panic, it will be removed when the scheduled task catches up or when you next request it through Redisson.
**Q: How can I perform Pipelining/Transaction through Redisson?**
**A** : The fact is pipelining and transaction are dealt with virtually in the same way by the `RBatch` object in Redisson. This is the design decision we took based on the analysis of the characteristics of both techniques. From the client side point of view, through both techniques, you are expected to issue a series of commands consecutively, and more importantly you will only expect to see the results after the last command is executed.
There are only subtle differences between the two techniques lies within the `RBatch` API. There is an `atomic()` method you should use before issuing batch commands if you want to execute a series of commands in a single transaction. There is no other usage difference.
And yes, if this answers your other question, transactional commands are always dispatched in a single pipeline.
**Q: Is Redisson thread safe? Can I share an instance of it between different threads?**
**A** : The Redisson instance itself and all the objects it provides are thread safe. APIs exposed by those objects are just operation handles. None of the these objects keep any states that would break the thread safety local to the instance. Most of those objects that do not “contain” any data local to the JVM with exception to LocalCached instances for obvious reasons. And here is a piece of pro advice: You can even share a RObject to multiple machines by publish it over a RTopic.
**Q: Can I use different encoder/decoders for different tasks?**
**A** : A different codec to the default one can be supplied when creating a `RObject` instance:
```java
RMap<String, String> map = redisson.getMap("myMap", new MyCodec());
```

@ -0,0 +1,81 @@
**1. Add dependency**
``` python
import tensorflow as tf
```
Maven
```xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle
```java
compile 'org.redisson:redisson:xVERSIONx'
```
SBT
```java
libraryDependencies += "org.redisson" % "redisson" % "xVERSIONx"
```
**2. Start development**
```java
// 1. Create config object
Config config = new Config();
config.useClusterServers()
// use "rediss://" for SSL connection
.addNodeAddress("redis://127.0.0.1:7181");
// or read config from file
config = Config.fromYAML(new File("config-file.yaml"));
```
```java
// 2. Create Redisson instance
// Sync and Async API
RedissonClient redisson = Redisson.create(config);
// Reactive API
RedissonReactiveClient redissonReactive = redisson.reactive();
// RxJava3 API
RedissonRxClient redissonRx = redisson.rxJava();
```
```java
// 3. Get Redis or Valkey based implementation of java.util.concurrent.ConcurrentMap
RMap<MyKey, MyValue> map = redisson.getMap("myMap");
RMapReactive<MyKey, MyValue> mapReactive = redissonReactive.getMap("myMap");
RMapRx<MyKey, MyValue> mapRx = redissonRx.getMap("myMap");
```
```java
// 4. Get Redis or Valkey based implementation of java.util.concurrent.locks.Lock
RLock lock = redisson.getLock("myLock");
RLockReactive lockReactive = redissonReactive.getLock("myLock");
RLockRx lockRx = redissonRx.getLock("myLock");
```
```java
// 4. Get Redis or Valkey based implementation of java.util.concurrent.ExecutorService
RExecutorService executor = redisson.getExecutorService("myExecutorService");
// over 50 Redis or Valkey based Java objects and services ...
```
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.

@ -0,0 +1,584 @@
## Spring Boot Starter
Integrates Redisson with Spring Boot library. Depends on [Spring Data Redis](#spring-data-redis) module.
Supports Spring Boot 1.3.x - 3.3.x
### Usage
**1. Add `redisson-spring-boot-starter` dependency into your project:**
Maven
```xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle
```groovy
compile 'org.redisson:redisson-spring-boot-starter:xVERSIONx'
```
`redisson-spring-boot-starter` depends on `redisson-spring-data` module compatible with the latest version of Spring Boot. Downgrade `redisson-spring-data` module if necessary to support previous Spring Boot versions:
|redisson-spring-data<br/>module name|Spring Boot<br/>version|
|----------------------------|-------------------|
|redisson-spring-data-16 |1.3.y |
|redisson-spring-data-17 |1.4.y |
|redisson-spring-data-18 |1.5.y |
|redisson-spring-data-2x |2.x.y |
|redisson-spring-data-3x |3.x.y |
For Gradle, you can downgrade to `redisson-spring-data-27` this way:
```groovy
implementation ("org.redisson:redisson-spring-boot-starter:xVERSIONx") {
exclude group: 'org.redisson', module: 'redisson-spring-data-33'
}
implementation "org.redisson:redisson-spring-data-27:xVERSIONx"
```
**2. Add settings into `application.settings` file**
Using common Spring Boot 3.x+ settings:
```yaml
spring:
data:
redis:
database:
host:
port:
password:
ssl:
timeout:
connectTimeout:
clientName:
cluster:
nodes:
sentinel:
master:
nodes:
```
Using common Spring Boot up to 2.7.x settings:
```yaml
spring:
redis:
database:
host:
port:
password:
ssl:
timeout:
connectTimeout:
clientName:
cluster:
nodes:
sentinel:
master:
nodes:
```
Using Redisson config file:
([single mode](configuration.md/#single-yaml-config-format),
[replicated mode](configuration.md/#replicated-yaml-config-format),
[cluster mode](configuration.md/#cluster-yaml-config-format),
[sentinel mode](configuration.md/#sentinel-yaml-config-format),
[proxy mode](configuration.md/#proxy-mode-yaml-config-format),
[multi cluster mode](configuration.md/#multi-cluster-yaml-config-format),
[multi sentinel mode](configuration.md/#multi-sentinel-yaml-config-format))
```yaml
spring:
redis:
redisson:
file: classpath:redisson.yaml
```
Using Redisson settings:
([single mode](configuration.md/#single-settings),
[replicated mode](configuration.md/#replicated-settings),
[cluster mode](configuration.md/#cluster-settings),
[sentinel mode](configuration.md/#sentinel-settings),
[proxy mode](configuration.md/#proxy-mode-settings),
[multi cluster mode](configuration.md/#multi-cluster-settings),
[multi sentinel mode](configuration.md/#multi-sentinel-settings))
```yaml
spring:
redis:
redisson:
config: |
clusterServersConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
failedSlaveReconnectionInterval: 3000
failedSlaveCheckInterval: 60000
password: null
subscriptionsPerConnection: 5
clientName: null
loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
slaveConnectionMinimumIdleSize: 24
slaveConnectionPoolSize: 64
masterConnectionMinimumIdleSize: 24
masterConnectionPoolSize: 64
readMode: "SLAVE"
subscriptionMode: "SLAVE"
nodeAddresses:
- "redis://127.0.0.1:7004"
- "redis://127.0.0.1:7001"
- "redis://127.0.0.1:7000"
scanInterval: 1000
pingConnectionInterval: 0
keepAlive: false
tcpNoDelay: false
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.Kryo5Codec> {}
transportMode: "NIO"
```
**3. Available Spring Beans:**
- `RedissonClient`
- `RedissonRxClient`
- `RedissonReactiveClient`
- `RedisTemplate`
- `ReactiveRedisTemplate`
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.
### FAQ
**Q: How to replace Netty version brought by Spring Boot?**
You need to define netty version in properties section of your Maven project.
```xml
<properties>
<netty.version>4.1.107.Final</netty.version>
</properties>
```
**Q: How to disable Redisson?**
You may not have Redis or Valkey in some environments. In this case Redisson can be disabled:
- Using Annotations
Spring Boot 2.7+
```java
@SpringBootApplication
@EnableAutoConfiguration(exclude = {
RedissonAutoConfigurationV2.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
```
Spring Boot up to 2.6
```java
@SpringBootApplication
@EnableAutoConfiguration(exclude = {
RedissonAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
```
- Using application.yml file
Spring Boot 2.7+
```yaml
spring:
autoconfigure:
exclude:
- org.redisson.spring.starter.RedissonAutoConfigurationV2
```
Spring Boot up to 2.6
```yaml
spring:
autoconfigure:
exclude:
- org.redisson.spring.starter.RedissonAutoConfiguration
```
{% include 'cache/Spring-cache.md' %}
## Spring Session
Please note that Redis or Valkey `notify-keyspace-events` setting should contain `Exg` letters to make Spring Session integration work.
Ensure you have Spring Session library in your classpath, add it if necessary:
**Maven**
```xml
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-33</artifactId>
<version>xVERSIONx</version>
</dependency>
```
**Gradle**
```gradle
compile 'org.springframework.session:spring-session-core:3.2.1'
compile 'org.redisson:redisson-spring-data-33:xVERSIONx'
```
### Spring Http Session configuration
Add configuration class which extends `AbstractHttpSessionApplicationInitializer` class:
```java
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Bean
public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
return new RedissonConnectionFactory(redisson);
}
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.create(config);
}
}
```
### Spring WebFluxs Session configuration
Add configuration class which extends `AbstractReactiveWebInitializer` class:
```java
@Configuration
@EnableRedisWebSession
public class SessionConfig extends AbstractReactiveWebInitializer {
@Bean
public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
return new RedissonConnectionFactory(redisson);
}
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.create(config);
}
}
```
### Spring Boot configuration
1. Add Spring Session Data Redis library in classpath:
Maven:
```xml
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>3.2.1</version>
</dependency>
```
Gradle:
```gradle
compile 'org.springframework.session:spring-session-data-redis:3.2.1'
```
2. Add Redisson Spring Data Redis library in classpath:
Maven:
```xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-33</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle:
```gradle
compile 'org.redisson:redisson-spring-data-33:xVERSIONx'
```
3. Define follow properties in spring-boot settings
```
spring.session.store-type=redis
spring.redis.redisson.file=classpath:redisson.yaml
spring.session.timeout.seconds=900
```
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.
## Spring Transaction Manager
Redisson provides implementation of both `org.springframework.transaction.PlatformTransactionManager` and `org.springframework.transaction.ReactiveTransactionManager` interfaces to participant in Spring transactions. See also [Transactions](Transactions.md) section.
### Spring Transaction Management
```java
@Configuration
@EnableTransactionManagement
public class RedissonTransactionContextConfig {
@Bean
public TransactionalBean transactionBean() {
return new TransactionalBean();
}
@Bean
public RedissonTransactionManager transactionManager(RedissonClient redisson) {
return new RedissonTransactionManager(redisson);
}
@Bean(destroyMethod="shutdown")
public RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.create(config);
}
}
public class TransactionalBean {
@Autowired
private RedissonTransactionManager transactionManager;
@Transactional
public void commitData() {
RTransaction transaction = transactionManager.getCurrentTransaction();
RMap<String, String> map = transaction.getMap("test1");
map.put("1", "2");
}
}
```
### Reactive Spring Transaction Management
```java
@Configuration
@EnableTransactionManagement
public class RedissonReactiveTransactionContextConfig {
@Bean
public TransactionalBean transactionBean() {
return new TransactionalBean();
}
@Bean
public ReactiveRedissonTransactionManager transactionManager(RedissonReactiveClient redisson) {
return new ReactiveRedissonTransactionManager(redisson);
}
@Bean(destroyMethod="shutdown")
public RedissonReactiveClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.createReactive(config);
}
}
public class TransactionalBean {
@Autowired
private ReactiveRedissonTransactionManager transactionManager;
@Transactional
public Mono<Void> commitData() {
Mono<RTransactionReactive> transaction = transactionManager.getCurrentTransaction();
return transaction.flatMap(t -> {
RMapReactive<String, String> map = t.getMap("test1");
return map.put("1", "2");
}).then();
}
}
```
## Spring Cloud Stream
_This feature is available only in [Redisson PRO](https://redisson.pro) edition._
Redisson implements Spring Cloud Stream integration based on the reliable Redis Stream structure for message delivery. To use Redis binder with Redisson you need to add [Spring Cloud Stream](https://spring.io/projects/spring-cloud-stream) Binder library in classpath:
Maven:
```xml
<dependency>
<groupId>pro.redisson</groupId>
<artifactId>spring-cloud-stream-binder-redisson</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle:
```gradle
compile 'pro.redisson:spring-cloud-stream-binder-redisson:xVERSIONx'
```
Compatible with Spring versions below.
Spring Cloud Stream | Spring Cloud | Spring Boot
-- | -- | --
4.1.x | 2023.0.x | 3.0.x, 3.1.x, 3.2.x
4.0.x | 2022.0.x | 3.0.x, 3.1.x, 3.2.x
3.2.x | 2021.0.x | 2.6.x, 2.7.x (Starting with 2021.0.3 of Spring Cloud)
3.1.x | 2020.0.x | 2.4.x, 2.5.x (Starting with 2020.0.3 of Spring Cloud)
### Receiving messages
Register the input binder (an event sink) for receiving messages as follows:
```java
@Bean
public Consumer<MyObject> receiveMessage() {
return obj -> {
// consume received object ...
};
}
```
Define channel id in the configuration file `application.properties`. Example for `receiveMessage` bean defined above connected to `my-channel` channel:
```
spring.cloud.stream.bindings.receiveMessage-in-0.destination=my-channel
```
### Publishing messages
Register the output binder (an event source) for publishing messages as follows:
```java
@Bean
public Supplier<MyObject> feedSupplier() {
return () -> {
// ...
return new MyObject();
};
}
```
Define channel id in the configuration file `application.properties`. Example for `feedSupplier` bean defined above connected to `my-channel` channel:
```
spring.cloud.stream.bindings.feedSupplier-out-0.destination=my-channel
spring.cloud.stream.bindings.feedSupplier-out-0.producer.useNativeEncoding=true
```
## Spring Data Redis
Integrates Redisson with Spring Data Redis library. Implements Spring Data's `RedisConnectionFactory` and `ReactiveRedisConnectionFactory` interfaces and allows to interact with Redis through `RedisTemplate` or `ReactiveRedisTemplate` object.
### Usage
1. Add `redisson-spring-data` dependency into your project:
Maven:
```xml
<dependency>
<groupId>org.redisson</groupId>
<!-- for Spring Data Redis v.1.6.x -->
<artifactId>redisson-spring-data-16</artifactId>
<!-- for Spring Data Redis v.1.7.x -->
<artifactId>redisson-spring-data-17</artifactId>
<!-- for Spring Data Redis v.1.8.x -->
<artifactId>redisson-spring-data-18</artifactId>
<!-- for Spring Data Redis v.2.0.x -->
<artifactId>redisson-spring-data-20</artifactId>
<!-- for Spring Data Redis v.2.1.x -->
<artifactId>redisson-spring-data-21</artifactId>
<!-- for Spring Data Redis v.2.2.x -->
<artifactId>redisson-spring-data-22</artifactId>
<!-- for Spring Data Redis v.2.3.x -->
<artifactId>redisson-spring-data-23</artifactId>
<!-- for Spring Data Redis v.2.4.x -->
<artifactId>redisson-spring-data-24</artifactId>
<!-- for Spring Data Redis v.2.5.x -->
<artifactId>redisson-spring-data-25</artifactId>
<!-- for Spring Data Redis v.2.6.x -->
<artifactId>redisson-spring-data-26</artifactId>
<!-- for Spring Data Redis v.2.7.x -->
<artifactId>redisson-spring-data-27</artifactId>
<!-- for Spring Data Redis v.3.0.x -->
<artifactId>redisson-spring-data-30</artifactId>
<!-- for Spring Data Redis v.3.1.x -->
<artifactId>redisson-spring-data-31</artifactId>
<!-- for Spring Data Redis v.3.2.x -->
<artifactId>redisson-spring-data-32</artifactId>
<!-- for Spring Data Redis v.3.3.x -->
<artifactId>redisson-spring-data-33</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle:
```groovy
// for Spring Data Redis v.1.6.x
compile 'org.redisson:redisson-spring-data-16:xVERSIONx'
// for Spring Data Redis v.1.7.x
compile 'org.redisson:redisson-spring-data-17:xVERSIONx'
// for Spring Data Redis v.1.8.x
compile 'org.redisson:redisson-spring-data-18:xVERSIONx'
// for Spring Data Redis v.2.0.x
compile 'org.redisson:redisson-spring-data-20:xVERSIONx'
// for Spring Data Redis v.2.1.x
compile 'org.redisson:redisson-spring-data-21:xVERSIONx'
// for Spring Data Redis v.2.2.x
compile 'org.redisson:redisson-spring-data-22:xVERSIONx'
// for Spring Data Redis v.2.3.x
compile 'org.redisson:redisson-spring-data-23:xVERSIONx'
// for Spring Data Redis v.2.4.x
compile 'org.redisson:redisson-spring-data-24:xVERSIONx'
// for Spring Data Redis v.2.5.x
compile 'org.redisson:redisson-spring-data-25:xVERSIONx'
// for Spring Data Redis v.2.6.x
compile 'org.redisson:redisson-spring-data-26:xVERSIONx'
// for Spring Data Redis v.2.7.x
compile 'org.redisson:redisson-spring-data-27:xVERSIONx'
// for Spring Data Redis v.3.0.x
compile 'org.redisson:redisson-spring-data-30:xVERSIONx'
// for Spring Data Redis v.3.1.x
compile 'org.redisson:redisson-spring-data-31:xVERSIONx'
// for Spring Data Redis v.3.2.x
compile 'org.redisson:redisson-spring-data-32:xVERSIONx'
// for Spring Data Redis v.3.3.x
compile 'org.redisson:redisson-spring-data-33:xVERSIONx'
```
2. Register `RedissonConnectionFactory` in Spring context:
```java
@Configuration
public class RedissonSpringDataConfig {
@Bean
public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
return new RedissonConnectionFactory(redisson);
}
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
return Redisson.create(config);
}
}
```
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@ -0,0 +1,30 @@
Redisson uses high-perfomance async and lock-free Java client for Redis or Valkey. It supports both async and sync modes. The most popular use case is to execute a command not supported by Redisson yet. Please make sure that required command is not supported already with [Redis or Valkey command mapping](commands-mapping.md) list. `org.redisson.client.protocol.RedisCommands` - contains all available commands. Code example:
``` java
// Use shared EventLoopGroup only if multiple clients are used
EventLoopGroup group = new NioEventLoopGroup();
RedisClientConfig config = new RedisClientConfig();
config.setAddress("redis://localhost:6379") // or rediss:// for ssl connection
.setPassword("myPassword")
.setDatabase(0)
.setClientName("myClient")
.setGroup(group);
RedisClient client = RedisClient.create(config);
RedisConnection conn = client.connect();
//or
CompletionStage<RedisConnection> connFuture = client.connectAsync();
// execute SET command in sync way
conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0);
// execute GET command in async way
conn.async(StringCodec.INSTANCE, RedisCommands.GET, "test");
conn.close()
// or
conn.closeAsync()
client.shutdown();
// or
client.shutdownAsync();
```

@ -0,0 +1,257 @@
## Spring Boot
For Spring Boot usage please refer to [Spring Boot](integration-with-spring.md/#spring-boot-starter) article.
## Micronaut
Redisson integrates with [Micronaut](https://micronaut.io/) framework.
Supports Micronaut 2.0.x - 4.x.x
### Usage
**1. Add `redisson-micronaut` dependency into your project:**
Maven
```xml
<dependency>
<groupId>org.redisson</groupId>
<!-- for Micronaut v2.0.x - v2.5.x -->
<artifactId>redisson-micronaut-20</artifactId>
<!-- for Micronaut v3.x.x -->
<artifactId>redisson-micronaut-30</artifactId>
<!-- for Micronaut v4.x.x -->
<artifactId>redisson-micronaut-40</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle
```groovy
// for Micronaut v2.0.x - v2.5.x
compile 'org.redisson:redisson-micronaut-20:xVERSIONx'
// for Micronaut v3.x.x
compile 'org.redisson:redisson-micronaut-30:xVERSIONx'
// for Micronaut v4.x.x
compile 'org.redisson:redisson-micronaut-40:xVERSIONx'
```
**2. Add settings into `application.yml` file**
Config structure is a Redisson YAML configuration -
[single mode](configuration.md/#single-yaml-config-format),
[replicated mode](configuration.md/#replicated-yaml-config-format),
[cluster mode](configuration.md/#cluster-yaml-config-format),
[sentinel mode](configuration.md/#sentinel-yaml-config-format),
[proxy mode](configuration.md/#proxy-mode-yaml-config-format),
[multi cluster mode](configuration.md/#multi-cluster-yaml-config-format),
[multi sentinel mode](configuration.md/#multi-sentinel-yaml-config-format)
NOTE: Setting names in camel case should be joined with hyphens (-).
Config example:
```yaml
redisson:
single-server-config:
address: "redis://127.0.0.1:6379"
threads: 16
netty-threads: 32
```
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.
### Cache
For Micronaut Cache usage please refer to [Micronaut Cache](cache-api-implementations.md/#micronaut-cache) article.
### Session
Redisson provides Micronanut [Session](https://docs.micronaut.io/latest/api/io/micronaut/session/Session.html) store implementation.
Extra settings to [HttpSessionConfiguration](https://docs.micronaut.io/2.5.4/api/io/micronaut/session/http/HttpSessionConfiguration.html) object:
|Setting name|Type|Description|
|------------|----|-----------|
|micronaut.session.http.redisson.enabled|java.lang.Boolean|Enables Session store|
|micronaut.session.http.redisson.key-prefix|java.lang.Integer|Defines string prefix applied to all objects stored in Redis.|
|micronaut.session.http.redisson.codec|java.lang.Class|Data codec applied to cache entries. Default is Kryo5Codec codec.|
|micronaut.session.http.redisson.update-mode|java.lang.String|Defines session attributes update mode.<br/>`WRITE_BEHIND` - session changes stored asynchronously.<br/>`AFTER_REQUEST` - session changes stored only on `SessionStore#save(Session)` method invocation. Default value.|
|micronaut.session.http.redisson.broadcastSessionUpdates|java.lang.Boolean|Defines broadcasting of session updates across all micronaut services.|
Config example:
```yaml
micronaut:
session:
http:
redisson:
enabled: true
update-mode: "WRITE_BEHIND"
broadcast-session-updates: false
```
## Quarkus
Redisson integrates with [Quarkus](https://quarkus.io/) framework and implements [Quarkus Cache](https://quarkus.io/guides/cache).
Supports Quarkus 1.6.x - 3.x.x
??? note "Native image with RemoteService. Click to expand"
To use RemoteService in native image add **dynamic-proxy.json** and **reflection-config.json** files in `quarkus.native.additional-build-args` setting.
```
-H:DynamicProxyConfigurationResources=dynamic-proxy.json,-H:ReflectionConfigurationFiles=reflection-config.json
```
dynamic-proxy.json:
```
[
["<Remote Service interface name>"]
]
```
reflection-config.json:
```
[
{
"name":"<Remote Service interface name>",
"allDeclaredMethods":true
}
]
```
### Usage
**1. Add `redisson-quarkus` dependency into your project:**
Maven
```xml
<dependency>
<groupId>org.redisson</groupId>
<!-- for Quarkus v1.6.x - v1.13.x -->
<artifactId>redisson-quarkus-16</artifactId>
<!-- for Quarkus v2.x.x -->
<artifactId>redisson-quarkus-20</artifactId>
<!-- for Quarkus v3.x.x -->
<artifactId>redisson-quarkus-30</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle
```groovy
// for Quarkus v1.6.x - v1.13.x
compile 'org.redisson:redisson-quarkus-16:xVERSIONx'
// for Quarkus v2.x.x
compile 'org.redisson:redisson-quarkus-20:xVERSIONx'
// for Quarkus v3.x.x
compile 'org.redisson:redisson-quarkus-30:xVERSIONx'
```
**2. Add settings into `application.properties` file**
Config structure is a flat Redisson YAML configuration -
[single mode](configuration.md/#single-yaml-config-format),
[replicated mode](configuration.md/#replicated-yaml-config-format),
[cluster mode](configuration.md/#cluster-yaml-config-format),
[sentinel mode](configuration.md/#sentinel-yaml-config-format),
[proxy mode](configuration.md/#proxy-mode-yaml-config-format),
[multi cluster mode](configuration.md/#multi-cluster-yaml-config-format),
[multi sentinel mode](configuration.md/#multi-sentinel-yaml-config-format)
NOTE: Setting names in camel case should be joined with hyphens (-).
Below is the configuration example for a single Redis or Valkey node setup.
```
quarkus.redisson.single-server-config.address=redis://localhost:6379
quarkus.redisson.single-server-config.password=null
quarkus.redisson.threads=16
quarkus.redisson.netty-threads=32
```
Use `quarkus.redisson.file` setting to specify path to a config file.
**3. Use Redisson**
```java
@Inject
RedissonClient redisson;
```
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.
### Cache
For Quarkus Cache usage please refer to [Quarkus Cache](cache-api-implementations.md/#quarkus-cache) article.
## Helidon
Redisson implements [Helidon](https://helidon.io/) CDI extension for Redis.
Supports Helidon 1.4.x - 4.x.x
### Usage
**1. Add `redisson-helidon` dependency into your project:**
Maven
```xml
<dependency>
<groupId>org.redisson</groupId>
<!-- for Helidon v1.4.x - v2.5.x -->
<artifactId>redisson-helidon-20</artifactId>
<!-- for Helidon v3.x.x -->
<artifactId>redisson-helidon-30</artifactId>
<!-- for Helidon v4.x.x -->
<artifactId>redisson-helidon-40</artifactId>
<version>xVERSIONx</version>
</dependency>
```
Gradle
```groovy
// for Helidon v1.4.x - v2.5.x
compile 'org.redisson:redisson-helidon-20:xVERSIONx'
// for Helidon v3.x.x
compile 'org.redisson:redisson-helidon-30:xVERSIONx'
// for Helidon v4.x.x
compile 'org.redisson:redisson-helidon-40:xVERSIONx'
```
**2. Add settings into `META-INF/microprofile-config.properties` file**
Config structure is a flat Redisson YAML configuration -
[single mode](configuration.md/#single-yaml-config-format),
[replicated mode](configuration.md/#replicated-yaml-config-format),
[cluster mode](configuration.md/#cluster-yaml-config-format),
[sentinel mode](configuration.md/#sentinel-yaml-config-format),
[proxy mode](configuration.md/#proxy-mode-yaml-config-format),
[multi cluster mode](configuration.md/#multi-cluster-yaml-config-format),
[multi sentinel mode](configuration.md/#multi-sentinel-yaml-config-format)
Below is the configuration example for Redisson instance named `simple`.
```
org.redisson.Redisson.simple.singleServerConfig.address=redis://127.0.0.1:6379
org.redisson.Redisson.simple.singleServerConfig.connectionPoolSize=64
org.redisson.Redisson.simple.threads=16
org.redisson.Redisson.simple.nettyThreads=32
```
**3. Use Redisson**
```java
@Inject
@Named("simple")
private RedissonClient redisson;
```
For injection without @Named annotation use instance name - `default`.
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.

@ -0,0 +1,33 @@
Redisson provides API to manage Redis or Valkey nodes.
Code example of operations with **Cluster** setup:
```java
RedisCluster cluster = redisson.getRedisNodes(RedisNodes.CLUSTER);
cluster.pingAll();
Collection<RedisClusterMaster> masters = cluster.getMasters();
Collection<RedisClusterMaster> slaves = cluster.getSlaves();
```
Code example of operations with **Master Slave** setup:
```java
RedisMasterSlave masterSlave = redisson.getRedisNodes(RedisNodes.MASTER_SLAVE);
masterSlave.pingAll();
RedisMaster master = masterSlave.getMaster();
Collection<RedisSlave> slaves = masterSlave.getSlaves();
```
Code example of operations with **Sentinel** setup:
```java
RedisSentinelMasterSlave sentinelMasterSlave = redisson.getRedisNodes(RedisNodes.SENTINEL_MASTER_SLAVE);
sentinelMasterSlave.pingAll();
RedisMaster master = sentinelMasterSlave.getMaster();
Collection<RedisSlave> slaves = sentinelMasterSlave.getSlaves();
Collection<RedisSentinel> sentinels = sentinelMasterSlave.getSentinels();
```
Code example of operations with **Single** setup:
```java
RedisSingle single = redisson.getRedisNodes(RedisNodes.SINGLE);
single.pingAll();
RedisMaster instance = single.getInstance();
```

@ -0,0 +1,711 @@
## Metrics
_This feature is available only in [Redisson PRO](https://redisson.pro)_
### Monitoring systems integration
Redisson provides integration the most popular monitoring systems through [Micrometer](https://micrometer.io/) framework.
**1. AppOptics**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-appoptics`
Class: `org.redisson.config.metrics.AppOpticsMeterRegistryProvider`
Parameters:
* `uri` - AppOptics host uri
* `hostTag` - tag mapped to host
* `apiToken` - AppOptics api token
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**2. Atlas**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-atlas`
Class: `org.redisson.config.metrics.AtlasMeterRegistryProvider`
Parameters:
* `uri` - Atlas host uri
* `configUri` - Atlas LWC endpoint uri to retrieve current subscriptions
* `evalUri` - Atlas LWC endpoint uri to evaluate the data for a subscription
* `numThreads` - number of threads used by scheduler (default is 4)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 10000)
**3. Azure**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-azure-monitor`
Class: `org.redisson.config.metrics.AzureMonitorMeterRegistryProvider`
Parameters:
* `instrumentationKey` - instrumentation key
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**4. Amazon CloudWatch**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-cloudwatch`
Class: `org.redisson.config.metrics.CloudWatchMeterRegistryProvider`
Parameters:
* `accessKey` - AWS access key
* `secretKey` - AWS secret access key
* `namespace` - namespace value
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**5. Datadog**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-datadog`
Class: `org.redisson.config.metrics.DatadogMeterRegistryProvider`
Parameters:
* `uri` - Datadog host uri
* `hostTag` - tag mapped to host
* `apiKey` - api key
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**6. Dropwizard**
Class: `org.redisson.config.metrics.DropwizardMeterRegistryProvider`
Parameters:
* `sharedRegistryName` - name used to store instance in `SharedMetricRegistries`
* `nameMapper` - custom implementation of `io.micrometer.core.instrument.util.HierarchicalNameMapper`
**7. Dynatrace**
Class: `org.redisson.config.metrics.DynatraceMeterRegistryProvider`
Parameters:
* `uri` - Dynatrace host uri
* `apiToken` - api token
* `deviceId` - device id
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**8. Elastic**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-elastic`
Class: `org.redisson.config.metrics.ElasticMeterRegistryProvider`
Parameters:
* `host` - Elasticsearch host uri
* `userName` - user name
* `password` - password
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**9. Ganglia**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-ganglia`
Class: `org.redisson.config.metrics.GangliaMeterRegistryProvider`
Parameters:
* `host` - Ganglia host address
* `port` - Ganglia port
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**10. Graphite**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-graphite`
Class: `org.redisson.config.metrics.GraphiteMeterRegistryProvider`
Parameters:
* `host` - Graphite host address
* `port` - Graphite port
**11. Humio**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-humio`
Class: `org.redisson.config.metrics.HumioMeterRegistryProvider`
Parameters:
* `uri` - Humio host uri
* `repository` - repository name
* `apiToken` - api token
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**12. Influx**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-influx`
Class: `org.redisson.config.metrics.InfluxMeterRegistryProvider`
Parameters:
* `uri` - Influx host uri
* `db` - db name
* `userName` - user name
* `password` - password
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**13. JMX**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-jmx`
Class: `org.redisson.config.metrics.JmxMeterRegistryProvider`
Parameters:
* `domain` - domain name
* `sharedRegistryName` - name used to store instance in `SharedMetricRegistries`
**14. Kairos**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-kairos`
Class: `org.redisson.config.metrics.KairosMeterRegistryProvider`
Parameters:
* `uri` - Kairos host uri
* `userName` - user name
* `password` - password
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**15. NewRelic**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-new-relic`
Class: `org.redisson.config.metrics.NewRelicMeterRegistryProvider`
Parameters:
* `uri` - NewRelic host uri
* `apiKey` - api key
* `accountId` - account id
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**16. Prometheus**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-prometheus`
Class: `org.redisson.config.metrics.MeterRegistryWrapper`
Parameters:
* `registry` - instance of `PrometheusMeterRegistry` object
**17. SingnalFx**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-signalfx`
Class: `org.redisson.config.metrics.SingnalFxMeterRegistryProvider`
Parameters:
* `apiHost` - SingnalFx host uri
* `accessToken` - access token
* `source` - application instance id
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 10 secs)
* `batchSize` - number of measurements sent per request (default is 500)
**18. Stackdriver**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-stackdriver`
Class: `org.redisson.config.metrics.StackdriverMeterRegistryProvider`
Parameters:
* `projectId` - project id
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
**19. Statsd**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-statsd`
Class: `org.redisson.config.metrics.StatsdMeterRegistryProvider`
Parameters:
* `host` - Statsd host address
* `port` - Statsd port
* `flavor` - metrics format ETSY/DATADOG/TELEGRAF/SYSDIG
**20. Wavefront**
Required dependency:
* groupId: `io.micrometer`
* artifactId: `micrometer-registry-wavefront`
Class: `org.redisson.config.metrics.WavefrontMeterRegistryProvider`
Parameters:
* `uri` - Wavefront host uri
* `source` - application instance id
* `apiToken` - api token
* `numThreads` - number of threads used by scheduler (default is 2)
* `step` - update interval in ISO-8601 format (default is 1 min)
* `batchSize` - number of measurements sent per request (default is 500)
### Config examples
**JMX config**
```java
Config config = ... // Redisson PRO config object
JmxMeterRegistryProvider provider = new JmxMeterRegistryProvider();
provider.setDomain("appStats");
config.setMeterRegistryProvider(provider);
```
**Prometheus config**
```java
Config config = ... // Redisson PRO config object
PrometheusMeterRegistry registry = ...
config.setMeterRegistryProvider(new MeterRegistryWrapper(registry));
```
**Dynatrace config**
```java
Config config = ... // Redisson PRO config object
DynatraceMeterRegistryProvider p = new DynatraceMeterRegistryProvider();
p.setApiToken("Hg3M0iadsQC2Pcjk6QIW0g");
p.setUri("https://qtd9012301.live.dynatrace.com/");
p.setDeviceId("myHost");
config.setMeterRegistryProvider(p);
```
**Influx config**
```java
Config config = ... // Redisson PRO config object
InfluxMeterRegistryProvider provider = new InfluxMeterRegistryProvider();
provider.setUri("http://localhost:8086/");
provider.setDb("myinfluxdb");
provider.setUserName("admin");
provider.setPassword("admin");
config.setMeterRegistryProvider(provider);
```
### YAML config examples
YAML config is appended to Redisson config.
**JMX config**
```yaml
meterRegistryProvider: !<org.redisson.config.metrics.JmxMeterRegistryProvider>
domain: "appStats"
```
**Dynatrace config**
```yaml
meterRegistryProvider: !<org.redisson.config.metrics.DynatraceMeterRegistryProvider>
apiToken: "Hg3M0iadsQC2Pcjk6QIW0g"
uri: "https://qtd9012301.live.dynatrace.com"
deviceId: "myHost"
```
**Influx config**
```yaml
meterRegistryProvider: !<org.redisson.config.metrics.InfluxMeterRegistryProvider>
uri: "http://localhost:8086/"
db: "myinfluxdb"
userName: "admin"
password: "admin"
```
### Metrics list
The following metrics are available:
**Configuration metrics**
* `redisson.license.expiration-year` - A Gauge of the number of the license expiration year
* `redisson.license.expiration-month` - A Gauge of the number of the license expiration month
* `redisson.license.expiration-day` - A Gauge of the number of the license expiration day
* `redisson.license.active-instances` - A Gauge of the number of active Redisson PRO clients
* `redisson.executor-pool-size` - A Gauge of the number of executor threads pool size
* `redisson.netty-pool-size` - A Gauge of the number of netty threads pool size
* `netty.eventexecutor.tasks.pending` - Number of pending tasks in Netty event executor
**Metrics per Redis or Valkey node**
Base name: `redisson.redis.<host>:<port>`
* `status` - A Gauge of the number value of Redis or Valkey node status [1 = connected, -1 = disconnected]
* `type` - A Gauge of the number value of Redis or Valkey node type [1 = MASTER, 2 = SLAVE, 3 = SENTINEL]
<br/>
* `total-response-bytes` - A Meter of the total amount of bytes received from Redis or Valkey
* `response-bytes` - A Histogram of the number of bytes received from Redis or Valkey
* `total-request-bytes` - A Meter of the total amount of bytes sent to Redis or Valkey
* `request-bytes` - A Histogram of the number of bytes sent to Redis or Valkey
<br/>
* `connections.active` - A Counter of the number of busy connections
* `connections.free` - A Counter of the number of free connections
* `connections.max-pool-size` - A Counter of the number of maximum connection pool size
* `connections.reconnected` - A Counter of the number of reconnected connections
* `connections.total` - A Counter of the number of total connections in pool
<br/>
* `operations.total` - A Meter of the number of total executed operations
* `operations.total-failed` - A Meter of the number of total failed operations
* `operations.total-successful` - A Meter of the number of total successful operations
* `operations.latency` - A Histogram of the number of operations latency in milliseconds
* `operations.retry-attempt` - A Histogram of the number of operations retry attempts
<br/>
* `publish-subscribe-connections.active` - A Counter of the number of active publish subscribe connections
* `publish-subscribe-connections.free` - A Counter of the number of free publish subscribe connections
* `publish-subscribe-connections.max-pool-size` - A Counter of the number of maximum publish subscribe connection pool size
* `publish-subscribe-connections.total` - A Counter of the number of total publish subscribe connections in pool
**Metrics per RRemoteService object**
Base name: `redisson.remote-service.<name>`
* `invocations.total` - A Meter of the number of total executed invocations
* `invocations.total-failed` - A Meter of the number of total failed to execute invocations
* `invocations.total-successful` - A Meter of the number of total successful to execute invocations
**Metrics per RExecutorService object**
Base name: `redisson.executor-service.<name>`
* `tasks.submitted` - A Meter of the number of submitted tasks
* `tasks.executed` - A Meter of the number of executed tasks
<br/>
* `workers.active` - A Gauge of the number of busy task workers
* `workers.free` - A Gauge of the number of free task workers
* `workers.total` - A Gauge of the number of total task workers
* `workers.tasks-executed.total` - A Meter of the number of total executed tasks by workers
* `workers.tasks-executed.total-failed` - A Meter of the number of total failed to execute tasks by workers
* `workers.tasks-executed.total-successful` - A Meter of the number of total successful to execute tasks by workers
**Metrics per RMap object**
Base name: `redisson.map.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
**Metrics per RMapCache object**
Base name: `redisson.map-cache.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
**Metrics per RMapCacheV2 object**
Base name: `redisson.map-cache-v2.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
**Metrics per RMapCacheNative object**
Base name: `redisson.map-cache-native.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
**Metrics per RClusteredMapCache object**
Base name: `redisson.clustered-map-cache.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
**Metrics per RClusteredMapCacheNative object**
Base name: `redisson.clustered-map-cache-native.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
**Metrics per RLocalCachedMap object**
Base name: `redisson.local-cached-map.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
<br/>
* `local-cache.hits` - A Meter of the number of get requests for data contained in local cache
* `local-cache.misses` - A Meter of the number of get requests for data contained in local cache
* `local-cache.evictions` - A Meter of the number of evictions for data contained in local cache
* `local-cache.size` - A Gauge of the number of local cache size
**Metrics per RClusteredLocalCachedMap object**
Base name: `redisson.clustered-local-cached-map.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
<br/>
* `local-cache.hits` - A Meter of the number of get requests for data contained in local cache
* `local-cache.misses` - A Meter of the number of get requests for data contained in local cache
* `local-cache.evictions` - A Meter of the number of evictions for data contained in local cache
* `local-cache.size` - A Gauge of the number of local cache size
**Metrics per RLocalCachedMapCache object**
Base name: `redisson.local-cached-map-cache.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
<br/>
* `local-cache.hits` - A Meter of the number of get requests for data contained in local cache
* `local-cache.misses` - A Meter of the number of get requests for data contained in local cache
* `local-cache.evictions` - A Meter of the number of evictions for data contained in local cache
* `local-cache.size` - A Gauge of the number of local cache size
**Metrics per RLocalCachedMapCacheV2 object**
Base name: `redisson.local-cached-map-cache-v2.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
<br/>
* `local-cache.hits` - A Meter of the number of get requests for data contained in local cache
* `local-cache.misses` - A Meter of the number of get requests for data contained in local cache
* `local-cache.evictions` - A Meter of the number of evictions for data contained in local cache
* `local-cache.size` - A Gauge of the number of local cache size
**Metrics per RLocalCachedMapCacheNative object**
Base name: `redisson.local-cached-map-cache-native.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
<br/>
* `local-cache.hits` - A Meter of the number of get requests for data contained in local cache
* `local-cache.misses` - A Meter of the number of get requests for data contained in local cache
* `local-cache.evictions` - A Meter of the number of evictions for data contained in local cache
* `local-cache.size` - A Gauge of the number of local cache size
**Metrics per RClusteredLocalCachedMapCache object**
Base name: `redisson.clustered-local-cached-map-cache.<name>`
* `hits` - A Meter of the number of get requests for data contained in cache
* `misses` - A Meter of the number of get requests for data not contained in cache
* `puts` - A Meter of the number of puts to the cache
* `removals` - A Meter of the number of removals from the cache
<br/>
* `local-cache.hits` - A Meter of the number of get requests for data contained in local cache
* `local-cache.misses` - A Meter of the number of get requests for data contained in local cache
* `local-cache.evictions` - A Meter of the number of evictions for data contained in local cache
* `local-cache.size` - A Gauge of the number of local cache size
**Metrics per RTopic object**
Base name: `redisson.topic.<name>`
* `messages-sent` - A Meter of the number of messages sent for topic
* `messages-received` - A Meter of the number of messages received for topic
**Metrics per RBucket object**
Base name: `redisson.bucket.<name>`
* `gets` - A Meter of the number of get operations executed for bucket object
* `sets` - A Meter of the number of set operations executed for bucket object
**Metrics per JCache object**
Base name: `redisson.JCache.<name>`
* `cache.evictions` - A Meter of the number of evictions for data contained in JCache
* `cache.puts` - A Meter of the number of puts to the JCache
* `hit.cache.gets` - A Meter of the number of get requests for data contained in JCache
* `miss.cache.gets` - A Meter of the number of get requests for data contained in JCache
## Tracing
_This feature is available only in [Redisson PRO](https://redisson.pro)_
Redisson provides integration with the most popular tracer libraries through [Micrometer Observation API](https://docs.micrometer.io/micrometer/reference/observation.html) and [Micrometer Tracing](https://docs.micrometer.io/tracing/reference/) framework. This feature allows to gather extra statistics about invoked Redisson methods: name, arguments, invocation path, duration and frequency.
Configuration metrics per Tracing event.
* `invocation` - Redisson method with arguments. Arguments are included only if `includeArgs` set `true`
* `object_name` - Redisson object name
* `address` - Redis or Valkey server address
* `username` - username used to connect to Redis or Valkey server
### OpenZipkin Brave
Configuration example:
```java
OkHttpSender sender = OkHttpSender.create("http://localhost:9411/api/v2/spans");
AsyncZipkinSpanHandler zipkinSpanHandler = AsyncZipkinSpanHandler.create(sender);
StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create();
Tracing tracing = Tracing.newBuilder()
.localServiceName("myservice")
.currentTraceContext(braveCurrentTraceContext)
.sampler(Sampler.ALWAYS_SAMPLE)
.addSpanHandler(zipkinSpanHandler)
.build();
config.setTracingProvider(new BraveTracingProvider(tracing));
```
Required dependencies:
1. groupId: `io.zipkin.reporter2`, artifactId: `zipkin-sender-okhttp3`
2. groupId: `io.zipkin.reporter2`, artifactId: `zipkin-reporter-brave`
### OpenTelemetry
Configuration example:
```java
SpanExporter spanExporter = new ZipkinSpanExporterBuilder()
.setSender(URLConnectionSender.create("http://localhost:9411/api/v2/spans"))
.build();
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
.build();
OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
.setPropagators(ContextPropagators.create(B3Propagator.injectingSingleHeader()))
.setTracerProvider(sdkTracerProvider)
.build();
io.opentelemetry.api.trace.Tracer otelTracer = openTelemetrySdk.getTracerProvider().get("io.micrometer.micrometer-tracing");
config.setTracingProvider(new OtelTracingProvider(otelTracer, openTelemetrySdk.getPropagators()));
```
Required dependencies:
1. groupId: `io.opentelemetry`, artifactId: `opentelemetry-exporter-zipkin`
2. groupId: `io.zipkin.reporter2`, artifactId: `zipkin-sender-urlconnection`

@ -0,0 +1,18 @@
Redisson is the Java Client and Real-Time Data Platform for [Redis](https://redis.io) or [Valkey](https://valkey.io). Providing the most convenient and easiest way to work with Redis or Valkey. Redisson objects provide an abstraction layer between Redis or Valkey and your Java code, which allowing maintain focus on data modeling and application logic.
Redisson is compatible with the following Redis and Valkey cloud providers:
* [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/Replication.html)
* [AWS ElastiCache Cluster](https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/Clusters.html)
* [Azure Redis Cache](https://azure.microsoft.com/en-us/services/cache/)
* [Google Cloud Memorystore for Redis](https://cloud.google.com/memorystore/docs/redis/)
* [HUAWEI Distributed Cache Service for Redis](https://www.huaweicloud.com/en-us/product/dcs.html)
* [Aiven Redis hosting](https://aiven.io/redis)
* [RLEC Multiple Active Proxy](https://docs.redislabs.com/latest/rs/administering/designing-production/networking/multiple-active-proxy/)
* and many others.
Use the [Redis or Valkey commands mapping](commands-mapping.md) table to find the Redisson method for a particular Redis or Valkey command.
Redisson is Based on the [Netty](http://netty.io/) framework and is [Redis](http://redis.io) 3.0+ and JDK 1.8+ compatible.
Try __[Redisson PRO](https://redisson.pro)__ with **advanced features** and **support by SLA**.

@ -0,0 +1,115 @@
Multiple commands can be sent in a batch using `RBatch` object in a single network call. Command batches allows to reduce the overall execution time of a group of commands. In Redis or Valkey this approach called [Pipelining](https://redis.io/topics/pipelining).
Follow options could be supplied during object creation:
```java
BatchOptions options = BatchOptions.defaults()
// Sets execution mode
//
// ExecutionMode.REDIS_READ_ATOMIC - Store batched invocations in Redis and execute them atomically as a single command
//
// ExecutionMode.REDIS_WRITE_ATOMIC - Store batched invocations in Redis and execute them atomically as a single command
//
// ExecutionMode.IN_MEMORY - Store batched invocations in memory on Redisson side and execute them on Redis. Default mode
//
// ExecutionMode.IN_MEMORY_ATOMIC - Store batched invocations on Redisson side and executes them atomically on Redis or Valkey as a single command
.executionMode(ExecutionMode.IN_MEMORY)
// Inform Redis or Valkey not to send reply back to client. This allows to save network traffic for commands with batch with big
.skipResult()
// Synchronize write operations execution across defined amount of Redis or Valkey slave nodes
//
// sync with 2 slaves with 1 second for timeout
.syncSlaves(2, 1, TimeUnit.SECONDS)
// Response timeout
.responseTimeout(2, TimeUnit.SECONDS)
// Retry interval for each attempt to send Redis or Valkey commands batch
.retryInterval(2, TimeUnit.SECONDS);
// Attempts amount to re-send Redis or Valkey commands batch if it wasn't sent due to network delays or other issues
.retryAttempts(4);
```
Result Batch object contains follow data:
```java
// list of result objects per command in batch
List<?> responses = res.getResponses();
// amount of successfully synchronized slaves during batch execution
int slaves = res.getSyncedSlaves();
```
Code example for **Sync / Async** mode:
```java
RBatch batch = redisson.createBatch(BatchOptions.defaults());
batch.getMap("test1").fastPutAsync("1", "2");
batch.getMap("test2").fastPutAsync("2", "3");
batch.getMap("test3").putAsync("2", "5");
RFuture<Long> future = batch.getAtomicLong("counter").incrementAndGetAsync();
batch.getAtomicLong("counter").incrementAndGetAsync();
// result could be acquired through RFuture object returned by batched method
// or
// through result list by corresponding index
future.whenComplete((res, exception) -> {
// ...
});
BatchResult res = batch.execute();
// or
Future<BatchResult> resFuture = batch.executeAsync();
List<?> list = res.getResponses();
Long result = list.get(4);
```
Code example of **[Reactive](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RTransactionReactive.html) interface** usage:
```java
RBatchReactive batch = redisson.createBatch(BatchOptions.defaults());
batch.getMap("test1").fastPut("1", "2");
batch.getMap("test2").fastPut("2", "3");
batch.getMap("test3").put("2", "5");
Mono<Long> commandMono = batch.getAtomicLongAsync("counter").incrementAndGet();
batch.getAtomicLongAsync("counter").incrementAndGet();
// result could be acquired through Reactive object returned by batched method
// or
// through result list by corresponding index
commandMono.doOnNext(res -> {
// ...
}).subscribe();
Mono<BatchResult> resMono = batch.execute();
resMono.doOnNext(res -> {
List<?> list = res.getResponses();
Long result = list.get(4);
// ...
}).subscribe();
```
Code example of **[RxJava3](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RTransactionRx.html) interface** usage:
```java
RBatchRx batch = redisson.createBatch(BatchOptions.defaults());
batch.getMap("test1").fastPut("1", "2");
batch.getMap("test2").fastPut("2", "3");
batch.getMap("test3").put("2", "5");
Single<Long> commandSingle = batch.getAtomicLongAsync("counter").incrementAndGet();
batch.getAtomicLongAsync("counter").incrementAndGet();
// result could be acquired through RxJava3 object returned by batched method
// or
// through result list by corresponding index
commandSingle.doOnSuccess(res -> {
// ...
}).subscribe();
Mono<BatchResult> resSingle = batch.execute();
resSingle.doOnSuccess(res -> {
List<?> list = res.getResponses();
Long result = list.get(4);
// ...
}).subscribe();
```
In cluster environment batch executed in map\reduce way. It aggregates commands for each node and sends them simultaneously, then result got from each node added to common result list.

@ -0,0 +1,107 @@
## LUA Scripting
Redisson provides `RScript` object to execute Lua script. It has atomicity property and used to process data on Redis or Valkey side. Script could be executed in two modes:
* `Mode.READ_ONLY` scripts are executed as read operation
* `Mode.READ_WRITE` scripts are executed as write operation
One of the follow types returned as a script result object:
* `ReturnType.BOOLEAN` - Boolean type.
* `ReturnType.INTEGER` - Integer type.
* `ReturnType.MULTI` - List type of user defined type.
* `ReturnType.STATUS` - Lua String type.
* `ReturnType.VALUE` - User defined type.
* `ReturnType.MAPVALUE` - Map value type.
* `ReturnType.MAPVALUELIST` - List of Map value type.
Code example:
```java
RBucket<String> bucket = redisson.getBucket("foo");
bucket.set("bar");
RScript script = redisson.getScript(StringCodec.INSTANCE);
String r = script.eval(Mode.READ_ONLY,
"return redis.call('get', 'foo')",
RScript.ReturnType.VALUE);
// execute the same script stored in Redis or Valkey lua script cache
// load lua script into Redis or Valkey cache to all master instances
String res = script.scriptLoad("return redis.call('get', 'foo')");
// res == 282297a0228f48cd3fc6a55de6316f31422f5d17
// call lua script by sha digest
Future<Object> r1 = redisson.getScript().evalShaAsync(Mode.READ_ONLY,
"282297a0228f48cd3fc6a55de6316f31422f5d17",
RScript.ReturnType.VALUE, Collections.emptyList());
```
## Functions
Redisson provides `RFunction` object to execute [Functions](https://redis.io/topics/functions-intro). It has atomicity property and used to process data on Redis or Valkey side. Function can be executed in two modes:
* `Mode.READ` executes function as read operation
* `Mode.WRITE` executes function as write operation
One of the follow types returned as a script result object:
* `ReturnType.BOOLEAN` - Boolean type
* `ReturnType.LONG` - Long type
* `ReturnType.LIST` - List type of user defined type.
* `ReturnType.STRING` - plain String type
* `ReturnType.VALUE` - user defined type
* `ReturnType.MAPVALUE` - Map Value type. Codec.getMapValueDecoder() and Codec.getMapValueEncoder() methods are used for data deserialization or serialization
* `ReturnType.MAPVALUELIST` - List type, which consists of objects of Map Value type. Codec.getMapValueDecoder() and Codec.getMapValueEncoder() methods are used for data deserialization or serialization
Code example:
```java
RFunction f = redisson.getFunction();
// load function
f.load("lib", "redis.register_function('myfun', function(keys, args) return args[1] end)");
// execute function
String value = f.call(RFunction.Mode.READ, "myfun", RFunction.ReturnType.STRING, Collections.emptyList(), "test");
```
Code example of <b>Async interface</b> usage:
```java
RFunction f = redisson.getFunction();
// load function
RFuture<Void> loadFuture = f.loadAsync("lib", "redis.register_function('myfun', function(keys, args) return args[1] end)");
// execute function
RFuture<String> valueFuture = f.callAsync(RFunction.Mode.READ, "myfun", RFunction.ReturnType.STRING, Collections.emptyList(), "test");
```
Code example of <b>Reactive interface</b> usage:
```java
RedissonReactiveClient redisson = redissonClient.reactive();
RFunctionReactive f = redisson.getFunction();
// load function
Mono<Void> loadMono = f.load("lib", "redis.register_function('myfun', function(keys, args) return args[1] end)");
// execute function
Mono<String> valueMono = f.callAsync(RFunction.Mode.READ, "myfun", RFunction.ReturnType.STRING, Collections.emptyList(), "test");
```
Code example of <b>RxJava3 interface</b> usage:
```java
RedissonRxClient redisson = redissonClient.rxJava();
RFunctionRx f = redisson.getFunction();
// load function
Completable loadMono = f.load("lib", "redis.register_function('myfun', function(keys, args) return args[1] end)");
// execute function
Maybe<String> valueMono = f.callAsync(RFunction.Mode.READ, "myfun", RFunction.ReturnType.STRING, Collections.emptyList(), "test");
```

@ -0,0 +1,125 @@
## Overview
Redisson offers ability to run as standalone node and participate in distributed computing. Such Nodes are used to run [MapReduce](data-and-services/services.md#mapreduce-service), [ExecutorService](data-and-services/services.md#executor-service), [ScheduledExecutorService](data-and-services/services.md#scheduled-executor-service) tasks or [RemoteService](data-and-services/services.md#remote-service) services. All tasks are kept in Redis until their execution moment.
Packaged as a single jar and could be downloaded [here](https://repo1.maven.org/maven2/org/redisson/redisson-all/).
![](https://redisson.org/architecture.png)
## Configuration
### Settings
Redisson node uses same [configuration](configuration.md) as Redisson framework with additional settings. Threads amount available for ExecutorService set through `threads` setting.
**mapReduceWorkers**
Default value: `0`
MapReduce workers amount.
`0 = current_processors_amount`
**executorServiceWorkers**
Default value: `null`
Map with <b>key</b> as service name and <b>value</b> as workers amount.
**redissonNodeInitializer**
Default value: `null`
Listener runs during Redisson node startup.
**beanFactory**
Default value: `null`
Defines Spring Bean Factory instance to execute tasks with Spring's '@Autowired', '@Value' or JSR-330's '@Inject' annotation.
### YAML config format
Below is the configuration example for cluster mode with appended Redisson node settings in YAML format.
```yaml
---
clusterServersConfig:
nodeAddresses:
- "//127.0.0.1:7004"
- "//127.0.0.1:7001"
- "//127.0.0.1:7000"
scanInterval: 1000
threads: 0
executorServiceWorkers:
myService1: 123
myService2: 421
redissonNodeInitializer: !<org.mycompany.MyRedissonNodeInitializer> {}
```
## Initialization listener
Redisson node allows to execute initialization logic during startup via `RedissonNodeInitializer` listener. It allows, for example, register your remote service implementations which should be available in Redisson node's classpath, or execute other useful logic. For example, notify all subscribers about new Redisson node is available.
```java
public class MyRedissonNodeInitializer implements RedissonNodeInitializer {
@Override
public void onStartup(RedissonNode redissonNode) {
RMap<String, Integer> map = redissonNode.getRedisson().getMap("myMap");
// ...
// or
redisson.getRemoteService("myRemoteService").register(MyRemoteService.class, new MyRemoteServiceImpl(...));
// or
reidsson.getTopic("myNotificationTopic").publish("New node has joined. id:" + redissonNode.getId() + " remote-server:" + redissonNode.getRemoteAddress());
}
}
```
## How to run
### As Embedded node
Redisson node can be embedded into your application:
```java
// Redisson config
Config config = ...
// Redisson Node config
RedissonNodeConfig nodeConfig = new RedissonNodeConfig(config);
Map<String, Integer> workers = new HashMap<String, Integer>();
workers.put("test", 1);
nodeConfig.setExecutorServiceWorkers(workers);
// create Redisson node
RedissonNode node = RedissonNode.create(nodeConfig);
// or create Redisson node with existing Redisson instance
RedissonNode node = RedissonNode.create(nodeConfig, redisson);
node.start();
//...
node.shutdown();
```
### From command-line
1. Download Redisson node jar [here](https://repo1.maven.org/maven2/org/redisson/redisson-all/)
2. Create yaml configuration file
3. Run node using follow command line:
`java -jar redisson-all.jar config.yaml`
don't forget to add `-Xmx` and `-Xms` params
### Using Docker
**with Redis or Valkey instance**
1. Run Redis
`docker run -d --name redis-node redis`
2. Redisson Node
`docker run -d --network container:redis-node -e JAVA_OPTS="<java-opts>" -v <path-to-config>:/opt/redisson-node/redisson.conf redisson/redisson-node`
`<path-to-config>` - path to YAML configuration of Redisson Node
`<java-opts>` - JVM params
**without Redis or Valkey instance**
1. Redisson Node
`docker run -d -e JAVA_OPTS="<java-opts>" -v <path-to-config>:/opt/redisson-node/redisson.conf redisson/redisson-node`
`<path-to-config>` - path to YAML configuration of Redisson Node
`<java-opts>` - JVM params

@ -0,0 +1,140 @@
## Transactions management
`RMap`, `RMapCache`, `RLocalCachedMap`, `RSet`, `RSetCache` and `RBucket` Redisson objects may participant in Transaction with ACID properties. It uses locks for write operations and maintains data modification operations list until `commit()` method is executed. Acquired locks are released after `rollback()` method execution. Implementation throws `org.redisson.transaction.TransactionException` in case of any error during commit/rollback execution.
Transaction isolation level is: `READ_COMMITTED`.
Follow Transaction options are available:
```java
TransactionOptions options = TransactionOptions.defaults()
// Synchronization data timeout between Redis or Valkey master participating in transaction and its slaves.
// Default is 5000 milliseconds.
.syncSlavesTimeout(5, TimeUnit.SECONDS)
// Response timeout
// Default is 3000 milliseconds.
.responseTimeout(3, TimeUnit.SECONDS)
// Defines time interval for each attempt to send transaction if it hasn't been sent already.
// Default is 1500 milliseconds.
.retryInterval(2, TimeUnit.SECONDS)
// Defines attempts amount to send transaction if it hasn't been sent already.
// Default is 3 attempts.
.retryAttempts(3)
// If transaction hasn't committed within <code>timeout</code> it will rollback automatically.
// Default is 5000 milliseconds.
.timeout(5, TimeUnit.SECONDS);
```
For execution in Redis or Valkey cluster use {} brackets for collocation data on the same slot otherwise CROSSSLOT error is thrown by Redis.
Code example for Redis or Valkey cluster:
```java
RMap<String, String> map = transaction.getMap("myMap{user:1}");
map.put("1", "2");
String value = map.get("3");
RSet<String> set = transaction.getSet("mySet{user:1}")
set.add(value);
```
Code example of **Sync / Async** exection:
```java
RedissonClient redisson = Redisson.create(config);
RTransaction transaction = redisson.createTransaction(TransactionOptions.defaults());
RMap<String, String> map = transaction.getMap("myMap");
map.put("1", "2");
String value = map.get("3");
RSet<String> set = transaction.getSet("mySet")
set.add(value);
try {
transaction.commit();
} catch(TransactionException e) {
transaction.rollback();
}
// or
RFuture<Void> future = transaction.commitAsync();
future.exceptionally(exception -> {
transaction.rollbackAsync();
});
```
Code example of **Reactive** exection:
```java
RedissonReactiveClient redisson = Redisson.create(config).reactive();
RTransactionReactive transaction = redisson.createTransaction(TransactionOptions.defaults());
RMapReactive<String, String> map = transaction.getMap("myMap");
map.put("1", "2");
Mono<String> mapGet = map.get("3");
RSetReactive<String> set = transaction.getSet("mySet")
set.add(value);
Mono<Void> mono = transaction.commit();
mono.onErrorResume(exception -> {
return transaction.rollback();
});
```
Code example of **RxJava3** exection:
```java
RedissonRxClient redisson = Redisson.create(config).rxJava();
RTransactionRx transaction = redisson.createTransaction(TransactionOptions.defaults());
RMapRx<String, String> map = transaction.getMap("myMap");
map.put("1", "2");
Maybe<String> mapGet = map.get("3");
RSetRx<String> set = transaction.getSet("mySet")
set.add(value);
Completable res = transaction.commit();
res.onErrorResumeNext(exception -> {
return transaction.rollback();
});
```
## XA Transactions
_This feature is available only in [Redisson PRO](https://redisson.pro) edition._
Redisson provides [XAResource](https://docs.oracle.com/javaee/7/api/javax/transaction/xa/XAResource.html) implementation to participate in JTA transactions. `RMap`, `RMapCache`, `RLocalCachedMap`, `RSet`, `RSetCache` and `RBucket` Redisson objects may participant in Transaction.
Transaction isolation level is: `READ_COMMITTED`.
For execution in Redis or Valkey cluster use {} brackets for collocation data on the same slot otherwise CROSSSLOT error is thrown by Redis.
Code example for Redis or Valkey cluster:
```java
RMap<String, String> map = transaction.getMap("myMap{user:1}");
map.put("1", "2");
String value = map.get("3");
RSet<String> set = transaction.getSet("mySet{user:1}")
set.add(value);
```
Code example:
```java
// transaction obtained from JTA compatible transaction manager
Transaction globalTransaction = transactionManager.getTransaction();
RXAResource xaResource = redisson.getXAResource();
globalTransaction.enlistResource(xaResource);
RTransaction transaction = xaResource.getTransaction();
RBucket<String> bucket = transaction.getBucket("myBucket");
bucket.set("simple");
RMap<String, String> map = transaction.getMap("myMap");
map.put("myKey", "myValue");
transactionManager.commit();
```
## Spring Transaction Manager
For Spring Transaction Manager usage please refer to [Spring Transaction Manager](integration-with-spring.md/#spring-transaction-manager) article.

@ -0,0 +1,89 @@
## Tomcat Session
Redisson implements Redis or Valkey based Tomcat Session Manager. It stores session of [Apache Tomcat](http://tomcat.apache.org) in Redis or Valkey and allows to distribute requests across a cluster of Tomcat servers. Implements non-sticky session management backed by Redis.
Supports Apache Tomcat 7.x, 8.x, 9.x, 10.x
Usage:
**1. Add session manager**
Add `RedissonSessionManager` in global context - `tomcat/conf/context.xml` or per application context - `tomcat/conf/server.xml`
```xml
<Manager className="org.redisson.tomcat.RedissonSessionManager"
configPath="${catalina.base}/redisson.conf"
readMode="REDIS" updateMode="DEFAULT" broadcastSessionEvents="false"
keyPrefix=""/>
```
`keyPrefix` - string prefix applied to all keys. Allows to connect different Tomcat environments to the same Redis or Valkey instance.
`readMode` - read Session attributes mode. Two modes are available:
* `MEMORY` - stores attributes into local Tomcat Session and Redis. Further Session updates propagated to local Tomcat Session using Redis-based events.
* `REDIS` - stores attributes into Redis or Valkey only. Default mode.
`broadcastSessionEvents` - if `true` then `sessionCreated` and `sessionDestroyed` events are broadcasted across all Tomcat instances and cause all registered HttpSessionListeners to be triggered. Default is `false`.
`broadcastSessionUpdates` - if `true` and `readMode=MEMORY` then session updates are broadcasted across all Tomcat instances. Default is `true`.
`updateMode` - Session attributes update mode. Two modes are available:
* `DEFAULT` - session attributes are stored into Redis or Valkey only through the `Session.setAttribute` method. Default mode.
* `AFTER_REQUEST`
* In `readMode=REDIS` all changes of session attributes made through the `Session.setAttribute` method are accumulated in memory and stored into Redis or Valkey only after the end of the request.
* In `readMode=MEMORY` all session attributes are always stored into Redis or Valkey after the end of the request regardless of the `Session.setAttribute` method invocation. It is useful in case when some objects stored in session change their own state without `Session.setAttribute` method execution. Updated attributes are removed from all other Session instances if `broadcastSessionUpdates=true` and reloaded from Redis or Valkey when these attributes are requested.
`configPath` - path to Redisson YAML config. See [configuration](configuration.md) page for more details. In case session manager is configured programatically, a config object can be passed using the `setConfig()` method
Shared Redisson instance
Amount of Redisson instances created by Tomcat for multiple contexts could be reduced through JNDI registry:
1. Add shared redisson instance produced by `JndiRedissonFactory` into `tomcat/conf/server.xml` in `GlobalNamingResources` tag area:
```xml
<GlobalNamingResources>
<Resource name="bean/redisson"
auth="Container"
factory="org.redisson.JndiRedissonFactory"
configPath="${catalina.base}/conf/redisson.yaml"
closeMethod="shutdown"/>
</GlobalNamingResources>
```
2. Add `JndiRedissonSessionManager` with resource link to redisson instance into `tomcat/conf/context.xml`
```xml
<ResourceLink name="bean/redisson"
global="bean/redisson"
type="org.redisson.api.RedissonClient" />
<Manager className="org.redisson.tomcat.JndiRedissonSessionManager"
readMode="REDIS"
jndiName="bean/redisson" />
```
**2. Copy two jars into `TOMCAT_BASE/lib` directory:**
[redisson-all-3.36.0.jar](https://repo1.maven.org/maven2/org/redisson/redisson-all/3.36.0/redisson-all-3.36.0.jar)
Tomcat 7.x - [redisson-tomcat-7-3.36.0.jar](https://repo1.maven.org/maven2/org/redisson/redisson-tomcat-7/3.36.0/redisson-tomcat-7-3.36.0.jar)
Tomcat 8.x - [redisson-tomcat-8-3.36.0.jar](https://repo1.maven.org/maven2/org/redisson/redisson-tomcat-8/3.36.0/redisson-tomcat-8-3.36.0.jar)
Tomcat 9.x - [redisson-tomcat-9-3.36.0.jar](https://repo1.maven.org/maven2/org/redisson/redisson-tomcat-9/3.36.0/redisson-tomcat-9-3.36.0.jar)
Tomcat 10.x - [redisson-tomcat-10-3.36.0.jar](https://repo1.maven.org/maven2/org/redisson/redisson-tomcat-10/3.36.0/redisson-tomcat-10-3.36.0.jar)
Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**.
## Spring Session
For Spring Session usage please refer to [Spring Session](integration-with-spring.md/#spring-session) article.
## Micronaut Session
For Micronaut Session usage please refer to [Micronaut Session](microservices-integration.md/#session) article.
Loading…
Cancel
Save