diff --git a/docs/src/main/asciidoc/infinispan-client.adoc b/docs/src/main/asciidoc/infinispan-client.adoc
index 46ae2b62bc806..3a01a42383fb2 100644
--- a/docs/src/main/asciidoc/infinispan-client.adoc
+++ b/docs/src/main/asciidoc/infinispan-client.adoc
@@ -62,17 +62,17 @@ Add the following properties to connect to Infinispan Server:
[source,properties]
----
-# Infinispan Server address
-quarkus.infinispan-client.server-list=localhost:11222
+quarkus.infinispan-client.server-list=localhost:11222 <1>
-# Authentication
-quarkus.infinispan-client.auth-username=admin
-quarkus.infinispan-client.auth-password=password
+quarkus.infinispan-client.auth-username=admin <2>
+quarkus.infinispan-client.auth-password=password <3>
-# Infinispan client intelligence
-# Use BASIC as a Docker for Mac workaround
-quarkus.infinispan-client.client-intelligence=BASIC
+quarkus.infinispan-client.client-intelligence=BASIC <4>
----
+<1> Sets Infinispan Server address list, separated with commas
+<2> Sets the authentication username
+<3> Sets the authentication password
+<4> Sets the client intelligence. Use BASIC as a workaround if using Docker for Mac.
.Running Infinispan Server
@@ -90,6 +90,31 @@ Infinispan Server also enables authentication and security authorization by defa
$ ./bin/cli.sh user create admin -p password
----
+=== Creating caches from the client
+
+When a cache is accessed from the client, if the cache does not exist in the Infinispan Server and you want
+to create it on first access, use one of the following properties:
+
+[source,properties]
+----
+quarkus.infinispan-client.cache.books.configuration-uri=cacheConfig.xml <1>
+quarkus.infinispan-client.cache.magazine.configuration= <2>
+----
+<1> The file name located under the `resources` folder that contains the configuration of the 'books' cache
+<2> The configuration of the 'magazine' cache as a plain text property
+
+If both `configuration-uri` and `configuration` are configured for the same cache with the same Quarkus profile,
+`configuration-uri` gets preference over `configuration`.
+
+If nothing is configured for a particular cache, it will be created with the following basic configuration:
+
+[source, xml]
+----
+
+
+
+----
+
=== Authentication mechanisms
You can use the following authentication mechanisms with the Infinispan client:
@@ -478,10 +503,28 @@ You can read more about https://infinispan.org/docs/stable/titles/developing/dev
== Near Caching
-Near caching is disabled by default, but you can enable it by setting the profile config property
-`quarkus.infinispan-client.near-cache-max-entries` to a value greater than 0. You can also configure
-a regular expression so that only a subset of caches have near caching applied through the
-`quarkus.infinispan-client.near-cache-name-pattern` attribute.
+Near caching is disabled by default, but you can enable it on a per cache basic by configuring the following properties:
+
+[source,properties]
+----
+quarkus.infinispan-client.cache.books.near-cache-mode=INVALIDATED <1>
+quarkus.infinispan-client.cache.books.near-cache-max-entries=200 <2>
+quarkus.infinispan-client.cache.books.near-cache-use-bloom-filter=true <3>
+----
+
+<1> Enables near caching for the 'books' cache by setting the mode to `INVALIDATED`
+<2> Sets the maximum number of entries that the near cache of the 'books' cache can hold before eviction occurs
+<3> Enables bloom filter for the 'books' cache
+
+=== Bounded near caching
+
+You should always use bounded near caches by specifying the maximum number of entries they can contain.
+
+=== Bloom filters
+
+If you need to optimize the performance for write operations by reducing the total number of invalidation messages,
+enable bloom filter. Bloom filters reside on Infinispan Server and keep track of the entries that the client has requested.
+They cannot be used with unbounded near cache: maximum number of entries must be defined when enabling bloom filters.
== Encryption
diff --git a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java
index 7b8c52d3ffbf4..f59c6dbd49ac9 100644
--- a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java
+++ b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java
@@ -25,6 +25,7 @@
import org.infinispan.client.hotrod.impl.ConfigurationProperties;
import org.infinispan.client.hotrod.logging.Log;
import org.infinispan.client.hotrod.logging.LogFactory;
+import org.infinispan.commons.configuration.XMLStringConfiguration;
import org.infinispan.commons.marshall.Marshaller;
import org.infinispan.commons.marshall.ProtoStreamMarshaller;
import org.infinispan.commons.util.Util;
@@ -43,6 +44,7 @@
public class InfinispanClientProducer {
private static final Log log = LogFactory.getLog(InfinispanClientProducer.class);
+ public static final String DEFAULT_CONFIG = "";
public static final String PROTOBUF_FILE_PREFIX = "infinispan.client.hotrod.protofile.";
public static final String PROTOBUF_INITIALIZERS = "infinispan.client.hotrod.proto-initializers";
@@ -324,20 +326,33 @@ public RemoteCache getRemoteCache(InjectionPoint injectionPoint, Re
final io.quarkus.infinispan.client.Remote remote = getRemoteAnnotation(annotationSet);
if (cacheManager != null && remote != null && !remote.value().isEmpty()) {
- return cacheManager.getCache(remote.value());
+ RemoteCache cache = cacheManager.getCache(remote.value());
+ if (cache == null) {
+ log.warn("Attempt to create cache using minimal default config");
+ return cacheManager.administration()
+ .getOrCreateCache(remote.value(), new XMLStringConfiguration(DEFAULT_CONFIG));
+ }
+ return cache;
}
if (cacheManager != null) {
- return cacheManager.getCache();
+ RemoteCache cache = cacheManager.getCache();
+ if (cache == null) {
+ log.warn("Attempt to create cache using minimal default config");
+ return cacheManager.administration()
+ .getOrCreateCache(remote.value(), new XMLStringConfiguration(DEFAULT_CONFIG));
+ }
+ return cache;
}
+ log.error("Unable to produce RemoteCache. RemoteCacheManager is null");
return null;
}
@Produces
- public CounterManager counterManager() {
- RemoteCacheManager cacheManager = remoteCacheManager();
+ public CounterManager counterManager(RemoteCacheManager cacheManager) {
if (cacheManager == null) {
+ log.error("Unable to produce CounterManager. RemoteCacheManager is null");
return null;
}
return RemoteCounterManagerFactory.asCounterManager(cacheManager);
diff --git a/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/CacheSetup.java b/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/CacheSetup.java
index f04c346a7fea5..b12c898043842 100644
--- a/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/CacheSetup.java
+++ b/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/CacheSetup.java
@@ -31,6 +31,7 @@
import org.infinispan.query.dsl.Query;
import org.infinispan.query.dsl.QueryFactory;
+import io.quarkus.infinispan.client.Remote;
import io.quarkus.runtime.StartupEvent;
@ApplicationScoped
@@ -40,10 +41,15 @@ public class CacheSetup {
public static final String DEFAULT_CACHE = "default";
public static final String MAGAZINE_CACHE = "magazine";
+ public static final String AUTHORS_CACHE = "authors";
@Inject
RemoteCacheManager cacheManager;
+ @Inject
+ @Remote(AUTHORS_CACHE)
+ RemoteCache authors;
+
private final Map matches = new ConcurrentHashMap<>();
private CountDownLatch waitUntilStarted = new CountDownLatch(1);
@@ -51,6 +57,7 @@ public class CacheSetup {
void onStart(@Observes StartupEvent ev) {
RemoteCache defaultCache = cacheManager.getCache(DEFAULT_CACHE);
RemoteCache magazineCache = cacheManager.getCache(MAGAZINE_CACHE);
+
defaultCache.addClientListener(new EventPrintListener());
ContinuousQuery continuousQuery = Search.getContinuousQuery(defaultCache);
@@ -81,8 +88,10 @@ public void resultUpdated(String key, Book value) {
log.info("Added continuous query listener");
+ Author gMartin = new Author("George", "Martin");
+
defaultCache.put("book1", new Book("Game of Thrones", "Lots of people perish", 2010,
- Collections.singleton(new Author("George", "Martin")), Type.FANTASY, new BigDecimal("23.99")));
+ Collections.singleton(gMartin), Type.FANTASY, new BigDecimal("23.99")));
defaultCache.put("book2", new Book("Game of Thrones Path 2", "They win?", 2023,
Collections.singleton(new Author("Son", "Martin")), Type.FANTASY, new BigDecimal("54.99")));
@@ -94,6 +103,8 @@ public void resultUpdated(String key, Book value) {
magazineCache.put("popular-time", new Magazine("TIME", YearMonth.of(1997, 4),
Arrays.asList("Yep, I'm gay", "Backlash against HMOS", "False Hope on Breast Cancer?")));
+ authors.put("aut-1", gMartin);
+
waitUntilStarted.countDown();
}
diff --git a/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/TestServlet.java b/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/TestServlet.java
index a1cec8db1b943..7352e9f637d16 100644
--- a/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/TestServlet.java
+++ b/integration-tests/infinispan-client/src/main/java/io/quarkus/it/infinispan/client/TestServlet.java
@@ -46,6 +46,10 @@ public class TestServlet {
@Remote(CacheSetup.MAGAZINE_CACHE)
RemoteCache magazineCache;
+ @Inject
+ @Remote(CacheSetup.AUTHORS_CACHE)
+ RemoteCache authorsCache;
+
@Inject
CounterManager counterManager;
@@ -234,4 +238,13 @@ public String magazineQuery(@PathParam("id") String name) {
.map(m -> m.getName() + ":" + m.getPublicationYearMonth())
.collect(Collectors.joining(",", "[", "]"));
}
+
+ @Path("create-cache-default-config/authors")
+ @GET
+ public String magazineQuery() {
+ cacheSetup.ensureStarted();
+ return authorsCache.values().stream()
+ .map(a -> a.getName())
+ .collect(Collectors.joining(",", "[", "]"));
+ }
}
diff --git a/integration-tests/infinispan-client/src/test/java/io/quarkus/it/infinispan/client/InfinispanClientFunctionalityTest.java b/integration-tests/infinispan-client/src/test/java/io/quarkus/it/infinispan/client/InfinispanClientFunctionalityTest.java
index c490f8d99ba63..9de116a8d3964 100644
--- a/integration-tests/infinispan-client/src/test/java/io/quarkus/it/infinispan/client/InfinispanClientFunctionalityTest.java
+++ b/integration-tests/infinispan-client/src/test/java/io/quarkus/it/infinispan/client/InfinispanClientFunctionalityTest.java
@@ -51,4 +51,9 @@ public void testNearCacheInvalidation() {
public void testQueryWithCustomMarshaller() {
RestAssured.when().get("/test/magazinequery/IM").then().body(is("[TIME:1923-03,TIME:1997-04]"));
}
+
+ @Test
+ public void testAuthor() {
+ RestAssured.when().get("/test/create-cache-default-config/authors").then().body(is("[George]"));
+ }
}