diff --git a/docs/README.md b/docs/README.md index 5f4fedcbf..435087ce9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Redisson - Easy Redis Java client
and Real-Time Data Platform +# Redisson - Valkey & Redis Java client
Complete Real-Time Data Platform High-performance async and lock-free Java client for Redis and Valkey based on [Netty](http://netty.io) framework. diff --git a/docs/data-and-services/collections.md b/docs/data-and-services/collections.md index da9bf04b7..c973ed873 100644 --- a/docs/data-and-services/collections.md +++ b/docs/data-and-services/collections.md @@ -667,15 +667,32 @@ multimap.destroy(); _This feature is available only in [Redisson PRO](https://redisson.pro) edition._ -Distributed Java implementation of Redis or Valkey based Key Value store for JSON objects. This object is thread-safe. Allows to store JSON value mapped by key. Operations can be executed per key or group of keys. Value is stored/retrieved using `JSON.*` commands. Both key and value are POJO objects. +[RJsonStore](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RJsonStore.html) is a distributed Key Value store for JSON objects. Compatible with Redis or Valkey. This object is thread-safe. Allows to store JSON value mapped by key. Operations can be executed per key or group of keys. Value is stored/retrieved using `JSON.*` commands. Both key and value are POJO objects. Allows to define `time to live` parameter per entry. Doesn't use an entry eviction task, entries are cleaned on Redis or Valkey side. -Implements **Async**, **Reactive** and **RxJava3** interfaces. +Code example of **[Async](https://www.javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RJsonStoreAsync.html) interface** usage: + +```java +RJsonStoreAsync store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class)); +``` + +Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RJsonStoreReactive.html) interface** usage: + +```java +RedissonReactiveClient redisson = redissonClient.reactive(); +RJsonStoreReactive bucket = redisson.getJsonStore("anyObject", new JacksonCodec<>(AnyObject.class)); +``` + +Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RJsonStoreRx.html) interface** usage: +```java +RedissonRxClient redisson = redissonClient.rxJava(); +RJsonStoreRx bucket = redisson.getJsonStore("anyObject", new JacksonCodec<>(AnyObject.class)); +``` Data write code example: ```java -RJsonStore store = redisson.getJsonStore("test", StringCodec.INSTANCE, new JacksonCodec(MyObject.class)); +RJsonStore store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class)); MyObject t1 = new MyObject(); t1.setName("name1"); @@ -705,7 +722,7 @@ store.setIfExists("1", t1); Data read code example: ```java -RJsonStore store = redisson.getJsonStore("test", StringCodec.INSTANCE, new JacksonCodec(MyObject.class)); +RJsonStore store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class)); // multiple entries at once Map entries = store.get(Set.of("1", "2")); @@ -717,7 +734,7 @@ MyObject value2 = store.get("2"); Data deletion code example: ```java -RJsonStore store = redisson.getJsonStore("test", StringCodec.INSTANCE, new JacksonCodec(MyObject.class)); +RJsonStore store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class)); // multiple entries at once long deleted = store.delete(Set.of("1", "2")); @@ -727,7 +744,22 @@ boolean status = store.delete("1"); boolean status = store.delete("2"); ``` -For data searching index prefix should be defined in `:` format. For example for object name "test" prefix is "test:". +Keys access code examples: +```java +RJsonStore store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class)); + +// iterate keys +Set keys = store.keySet(); + +// read all keys at once +Set keys = store.readAllKeySet(); +``` + +### Search by Object properties + +For data searching, index prefix should be defined in `:` format. For example for object name "test" prefix is "test:". + +`StringCodec` should be used as object codec to enable searching by field. Data search code example: ```java @@ -758,17 +790,6 @@ AggregationResult ar = s.aggregate("idx", "*", AggregationOptions.defaults() .withCursor().load("name")); ``` -Keys access code examples: -```java -RJsonStore store = redisson.getJsonStore("test", StringCodec.INSTANCE, new JacksonCodec(MyObject.class)); - -// iterate keys -Set keys = store.keySet(); - -// read all keys at once -Set keys = store.readAllKeySet(); -``` - ### Local Cache Redisson provides [JSON Store](#json-store) implementation with local cache. @@ -912,54 +933,6 @@ boolean status = store.delete("1"); boolean status = store.delete("2"); ``` -For data searching index prefix should be defined in `:` format. For example for object name "test" prefix is "test:". - -Data search code example: -```java -RSearch s = redisson.getSearch(); -s.createIndex("idx", IndexOptions.defaults() - .on(IndexType.JSON) - .prefix(Arrays.asList("test:")), - FieldIndex.text("name")); - -LocalCachedJsonStoreOptions ops = LocalCachedJsonStoreOptions.name("test") - .keyCodec(StringCodec.INSTANCE) - .valueCodec(new JacksonCodec<>(MyObject.class)); -RLocalCachedJsonStore store = redisson.getLocalCachedJsonStore(ops); - -MyObject t1 = new MyObject(); -t1.setName("name1"); -MyObject t2 = new MyObject(); -t2.setName("name2"); - -Map entries = new HashMap<>(); -entries.put("1", t1); -entries.put("2", t2); -store.set(entries); - -// search -SearchResult r = s.search("idx", "*", QueryOptions.defaults() - .returnAttributes(new ReturnAttribute("name"))); - -// aggregation -AggregationResult ar = s.aggregate("idx", "*", AggregationOptions.defaults() - .withCursor().load("name")); -``` - -Keys access code examples: -```java -LocalCachedJsonStoreOptions ops = LocalCachedJsonStoreOptions.name("test") - .keyCodec(StringCodec.INSTANCE) - .valueCodec(new JacksonCodec<>(MyObject.class)); -RLocalCachedJsonStore store = redisson.getLocalCachedJsonStore(ops); - -// iterate keys -Set keys = store.keySet(); - -// read all keys at once -Set keys = store.readAllKeySet(); -``` - ## Set Redis or Valkey based [Set](https://static.javadoc.io/org.redisson/redisson/latest/org/redisson/api/RSet.html) object for Java implements [Set](https://docs.oracle.com/javase/8/docs/api/java/util/Set.html) interface. This object is thread-safe. Keeps elements uniqueness via element state comparison. Set size limited to `4 294 967 295` elements. Redis or Valkey uses serialized state to check value uniqueness instead of value's `hashCode()`/`equals()` methods. diff --git a/docs/data-and-services/objects.md b/docs/data-and-services/objects.md index 6e4b89a9d..3a091025d 100644 --- a/docs/data-and-services/objects.md +++ b/docs/data-and-services/objects.md @@ -290,26 +290,11 @@ 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
method name | Local cache | Ultra-fast
read/write | -| ------------- | :-----------: | :---------:| -|getJsonBucket()
open-source version | ❌ | ❌ | -|getJsonBucket()
[Redisson PRO](https://redisson.pro) version | ❌ | ✔️ | -|getLocalCachedJsonBucket()
[Redisson PRO](https://redisson.pro) version | ✔️ | ✔️ | +Use [JSON Store](collections.md/#json-store) for key-value implementation and local cache support. Code example: ```java RJsonBucket bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); -// or local cached instance -RLocalCachedJsonBucket bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); - bucket.set(new AnyObject(1)); AnyObject obj = bucket.get(); @@ -325,8 +310,6 @@ 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 bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); -// or local cached instace -RLocalCachedJsonBucket bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); RFuture future = bucket.setAsync(new AnyObject(1)); RFuture objfuture = bucket.getAsync(); @@ -343,9 +326,6 @@ Code example of **[Reactive](https://static.javadoc.io/org.redisson/redisson/lat ```java RedissonReactiveClient redisson = redissonClient.reactive(); RJsonBucketReactive bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); -// or local cached instance -RLocalCachedJsonBucketReactive bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); - Mono mono = bucket.set(new AnyObject(1)); Mono objMono = bucket.get(); @@ -362,8 +342,6 @@ Code example of **[RxJava3](https://static.javadoc.io/org.redisson/redisson/late ```java RedissonRxClient redisson = redissonClient.rxJava(); RJsonBucketRx bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); -// or local cached instance -RLocalCachedJsonBucketRx bucket = redisson.getLocalCachedJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); Completable rx = bucket.set(new AnyObject(1)); Maybe objRx = bucket.get(); diff --git a/docs/data-and-services/services.md b/docs/data-and-services/services.md index 1cd628421..582b09d1d 100644 --- a/docs/data-and-services/services.md +++ b/docs/data-and-services/services.md @@ -274,11 +274,11 @@ public class MyObject { } ``` -Please note: fields marked with `transient` keyword aren't stored in Redis. +Please note: fields marked with `transient` keyword aren't stored in Redis or Valkey. To start use it you should use one of methods below: -`RLiveObjectService.attach()` - attaches object to Redis. Discard all the field values already in the detached instance +`RLiveObjectService.attach()` - attaches object to Redis or Valkey. Discard all the field values already in the detached instance `RLiveObjectService.merge()` - overrides current object state in Redis or Valkey with the given object state `RLiveObjectService.persist()` - stores only new object @@ -288,11 +288,11 @@ Code example: RLiveObjectService service = redisson.getLiveObjectService(); MyLiveObject myObject = new MyLiveObject(); myObject1.setId("1"); -// current state of myObject is now persisted and attached to Redis +// current state of myObject is now persisted and attached to Redis or Valkey myObject = service.persist(myObject); MyLiveObject myObject = new MyLiveObject("1"); -// current state of myObject is now cleared and attached to Redis +// current state of myObject is now cleared and attached to Redis or Valkey myObject = service.attach(myObject); MyLiveObject myObject = new MyLiveObject(); @@ -335,13 +335,13 @@ List.class | RedissonList.class The conversion prefers the one nearer to the top of the table if a field type matches more than one entries. i.e. `LinkedList` implements `Deque`, `List`, `Queue`, it will be converted to a `RedissonDeque` because of this. -Instances of these Redisson classes retains their states/values/entries in Redis or Valkey too, changes to them are directly reflected into Redis or Valkey without keeping values in local VM. +Instances of these Redisson classes retains their states/values/entries in Redis or Valkey too, changes to them are directly reflected into database without keeping values in local VM. ### Search by Object properties -Redisson provides comprehensive search engine for Live Object. To make a property participate in search it should be annotated with `@RIndex` annotation. +Redisson provides comprehensive search engine for RLO objects. To make a property participate in search it should be annotated with `@RIndex` annotation. -!!! note "Open-source version of search engine is slow" +!!! note "The open-source version of the search engine is not optimized!" Use [Redisson PRO](https://redisson.pro) for **ultra-fast search engine**, **low JVM memory consumption during search process** and **search index partitiong in cluster**. Usage example: @@ -366,14 +366,14 @@ public class MyObject { Different type of search conditions are available: -`Conditions.and` - **AND** condition for collection of nested conditions -`Conditions.eq` - **EQUALS** condition which restricts property to defined value -`Conditions.or` - **OR** condition for collection of nested conditions -`Conditions.in` - **IN** condition which restricts property to set of defined values -`Conditions.gt` - **GREATER THAN** condition which restricts property to defined value -`Conditions.ge` - **GREATER THAN ON EQUAL** condition which restricts property to defined value -`Conditions.lt` - **LESS THAN** condition which restricts property to defined value -`Conditions.le` - **LESS THAN ON EQUAL** condition which restricts property to defined value +`Conditions.and()` - **AND** condition for collection of nested conditions +`Conditions.eq()` - **EQUALS** condition which restricts property to defined value +`Conditions.or()` - **OR** condition for collection of nested conditions +`Conditions.in()` - **IN** condition which restricts property to set of defined values +`Conditions.gt()` - **GREATER THAN** condition which restricts property to defined value +`Conditions.ge()` - **GREATER THAN ON EQUAL** condition which restricts property to defined value +`Conditions.lt()` - **LESS THAN** condition which restricts property to defined value +`Conditions.le()` - **LESS THAN ON EQUAL** condition which restricts property to defined value Once object stored in Redis or Valkey we can run search: @@ -392,6 +392,73 @@ Collection objects = liveObjectService.find(MyObject.class, Search index expires after `expireXXX()` method call only if the Redis or Valkey `notify-keyspace-events` setting contains the letters `Kx`. +### Local Cache + +_This feature is available only in [Redisson PRO](https://redisson.pro) edition._ + +RLO objects can be cached in local cache on the Redisson side. + +**local cache** - so called near cache used to speed up read operations and avoid network roundtrips. It caches JSON Store entries on Redisson side and executes read operations up to **45x faster** in comparison with regular implementation. Local cached instances with the same name are 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. + +To make an RLO entity stored in local cache it should be annotated with `@RCache` annotation. + +`@RCache` annotation settings: + +* `storeCacheMiss` - defines whether to store a cache miss into the local cache. Default value is `false`. +* `storeMode` - defines store mode of cache data. Default value is `LOCALCACHE_REDIS`. Follow options are available: + * `LOCALCACHE` - store data in local cache only and use Redis or Valkey only for data update/invalidation. + * `LOCALCACHE_REDIS` - store data in both Redis or Valkey and local cache. +* `cacheProvider` - defines Cache provider used as local cache store. Default value is `REDISSON`. Follow options are available: + * `REDISSON` - uses Redisson own implementation + * `CAFFEINE` - uses Caffeine implementation +* `evictionPolicy` - defines local cache eviction policy. Default value is `NONE`. 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 soft references, entries are removed by GC + * `WEAK` - uses weak references, entries are removed by GC + * `NONE` - no eviction +* `cacheSize` - local cache size. If cache size is `0` then local cache is unbounded. If size is `-1` then local cache is always empty and doesn't store data. Default value is `0`. +* `reconnectionStrategy` - defines strategy for load missed local cache updates after connection failure. Default value is `NONE`. Follow options are available: + * `CLEAR` - clear local cache if map instance has been disconnected for a while. + * `NONE` - no reconnection handling +* `syncStrategy` - defines local cache synchronization strategy. Default value is `INVALIDATE`. Follow options are available: + * `INVALIDATE` - Default. Invalidate cache entry across all RLocalCachedJsonStore instances on map entry change + * `UPDATE` - Insert/update cache entry across all RLocalCachedJsonStore instances on map entry change + * `NONE` - No synchronizations on map changes +* `timeToLive` - defines time to live for each entry in local cache +* `maxIdle` - defines max idle time for each entry in local cache +* `useTopicPattern` - defines whether to use a global topic pattern listener that applies to all local cache instances belonging to the same Redisson instance. Default value is `true`. + +Usage example: + +```java +@REntity +@RCache(cacheSize = 10, evictionPolicy = EvictionPolicy.LRU) +public class MyObject { + + @RId + private String id; + + private String name; + + private Integer counter; + +} + + +RLiveObjectService service = redisson.getLiveObjectService(); + +MyObject obj = new MyObject(); +obj.setId("1"); +obj.setName("Simple name"); + +// current state of myObject is now persisted and attached to Redis or Valkey +myObject = service.persist(obj); + +// loaded from local cache +String n = myObject.getName(); +``` + ### Advanced Usage As described before, RLO classes are proxy classes which can be fabricated when needed and then get cached in a `RedissonClient` instance against its original class. This process can be a bit slow and it is recommended to pre-register all the Redisson Live Object classes via `RedissonLiveObjectService` for any kind of delay-sensitive applications. The service can also be used to unregister a class if it is no longer needed. And of course it can be used to check if the class has already been registered.