Skip to content

Commit

Permalink
Create Infinispan caches on first access with the minimal config if t…
Browse files Browse the repository at this point in the history
…hey don't exist
  • Loading branch information
karesti committed Sep 12, 2022
1 parent 1983f5e commit 1367a73
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 17 deletions.
66 changes: 54 additions & 12 deletions docs/src/main/asciidoc/infinispan-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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 by coma
<2> Sets the authentication username
<3> Sets the authentication password
<4> Sets the client intelligence. Use BASIC as a Docker for Mac workaround

.Running Infinispan Server

Expand All @@ -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 in 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=<distributed-cache><encoding media-type="application/x-protostream"/></distributed-cache> <2>
----
<1> The file name located under the `resources` folder taht contains the configuration of the cache 'books'
<2> The configuration of the cache 'magazine' 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]
----
<distributed-cache>
<encoding media-type="application/x-protostream"/>
</distributed-cache>
----

=== Authentication mechanisms

You can use the following authentication mechanisms with the Infinispan client:
Expand Down Expand Up @@ -478,10 +503,27 @@ 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 per cache configuring the following properties per cache.

[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 cache named 'books' by setting the mode to INVALIDATED
<2> Sets the maximum number of entries that the near cache of the cache 'books' can hold before eviction occurs
<3> Enables bloom filter for the cache 'books'

=== 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -43,6 +44,7 @@
public class InfinispanClientProducer {
private static final Log log = LogFactory.getLog(InfinispanClientProducer.class);

public static final String DEFAULT_CONFIG = "<distributed-cache><encoding media-type=\"application/x-protostream\"/></distributed-cache>";
public static final String PROTOBUF_FILE_PREFIX = "infinispan.client.hotrod.protofile.";
public static final String PROTOBUF_INITIALIZERS = "infinispan.client.hotrod.proto-initializers";

Expand Down Expand Up @@ -324,20 +326,33 @@ public <K, V> RemoteCache<K, V> 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<K, V> 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<K, V> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -40,17 +41,23 @@ 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<String, Author> authors;

private final Map<String, Book> matches = new ConcurrentHashMap<>();

private CountDownLatch waitUntilStarted = new CountDownLatch(1);

void onStart(@Observes StartupEvent ev) {
RemoteCache<String, Book> defaultCache = cacheManager.getCache(DEFAULT_CACHE);
RemoteCache<String, Magazine> magazineCache = cacheManager.getCache(MAGAZINE_CACHE);

defaultCache.addClientListener(new EventPrintListener());

ContinuousQuery<String, Book> continuousQuery = Search.getContinuousQuery(defaultCache);
Expand Down Expand Up @@ -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")));

Expand All @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public class TestServlet {
@Remote(CacheSetup.MAGAZINE_CACHE)
RemoteCache<String, Magazine> magazineCache;

@Inject
@Remote(CacheSetup.AUTHORS_CACHE)
RemoteCache<String, Author> authorsCache;

@Inject
CounterManager counterManager;

Expand Down Expand Up @@ -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(",", "[", "]"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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]"));
}
}

0 comments on commit 1367a73

Please sign in to comment.