Infinispan 15.0.3.Final

Closes #29068

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
Pedro Ruivo 2024-04-13 18:38:33 +01:00 committed by Alexander Schwartz
parent 8ff1ae0c08
commit cbce548e71
32 changed files with 170 additions and 303 deletions

View file

@ -92,16 +92,12 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId> <artifactId>infinispan-cachestore-remote</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View file

@ -88,11 +88,6 @@
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId> <artifactId>infinispan-cachestore-remote</artifactId>
</dependency> </dependency>
<dependency>
<!-- adding it explictly, as Keycloak's parent excludes it to have full control over Jakarta EE vs. Java EE -->
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View file

@ -16,6 +16,14 @@
*/ */
package org.keycloak.adapters.saml.elytron.infinispan; package org.keycloak.adapters.saml.elytron.infinispan;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
import org.jboss.logging.Logger;
import org.keycloak.adapters.saml.AdapterConstants; import org.keycloak.adapters.saml.AdapterConstants;
import org.keycloak.adapters.spi.SessionIdMapper; import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapperUpdater; import org.keycloak.adapters.spi.SessionIdMapperUpdater;
@ -23,14 +31,6 @@ import org.keycloak.adapters.spi.SessionIdMapperUpdater;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
import org.jboss.logging.Logger;
import java.util.Set; import java.util.Set;
/** /**
@ -94,21 +94,19 @@ public class InfinispanSessionCacheIdMapperUpdater {
} }
Cache<String, String[]> ssoCache = cacheManager.getCache(cacheName, true); Cache<String, String[]> ssoCache = cacheManager.getCache(cacheName, true);
final SsoSessionCacheListener listener = new SsoSessionCacheListener(ssoCache, mapper); SsoSessionCacheListener listener = new SsoSessionCacheListener(ssoCache, mapper);
ssoCache.addListener(listener); ssoCache.addListener(listener);
addSsoCacheCrossDcListener(ssoCache, listener); addSsoCacheCrossDcListener(ssoCache, listener);
LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, cacheName); LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, cacheName);
SsoCacheSessionIdMapperUpdater updater = new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater) { return new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater) {
@Override @Override
public void close() throws Exception { public void close() {
ssoCache.stop(); ssoCache.stop();
} }
}; };
return updater;
} catch (NamingException ex) { } catch (NamingException ex) {
LOG.warnv("Failed to obtain distributed session cache container, lookup={0}", cacheContainerLookup); LOG.warnv("Failed to obtain distributed session cache container, lookup={0}", cacheContainerLookup);
return previousIdMapperUpdater; return previousIdMapperUpdater;
@ -137,7 +135,7 @@ public class InfinispanSessionCacheIdMapperUpdater {
return; return;
} }
final Set<RemoteStore> stores = getRemoteStores(ssoCache); Set<RemoteStore> stores = getRemoteStores(ssoCache);
if (stores == null || stores.isEmpty()) { if (stores == null || stores.isEmpty()) {
return; return;
} }
@ -149,7 +147,7 @@ public class InfinispanSessionCacheIdMapperUpdater {
} }
} }
public static Set<RemoteStore> getRemoteStores(Cache ispnCache) { public static Set<RemoteStore> getRemoteStores(Cache<?, ?> ispnCache) {
return ispnCache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class); return ComponentRegistry.componentOf(ispnCache, PersistenceManager.class).getStores(RemoteStore.class);
} }
} }

View file

@ -224,7 +224,7 @@ spec:
expose: expose:
type: Route type: Route
configMapName: "cluster-config" configMapName: "cluster-config"
image: quay.io/infinispan/server:14.0.27.Final image: quay.io/infinispan/server:15.0.3.Final
configListener: configListener:
enabled: false enabled: false
container: container:

View file

@ -363,7 +363,7 @@ spec:
expose: expose:
type: Route type: Route
configMapName: "cluster-config" configMapName: "cluster-config"
image: quay.io/infinispan/server:14.0.27.Final image: quay.io/infinispan/server:15.0.3.Final
configListener: configListener:
enabled: false enabled: false
container: container:

View file

@ -363,7 +363,7 @@ spec:
expose: expose:
type: Route type: Route
configMapName: "cluster-config" configMapName: "cluster-config"
image: quay.io/infinispan/server:14.0.27.Final image: quay.io/infinispan/server:15.0.3.Final
configListener: configListener:
enabled: false enabled: false
container: container:

View file

@ -59,11 +59,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>

View file

@ -20,13 +20,11 @@ package org.keycloak.cluster.infinispan;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException; import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.lifecycle.ComponentStatus; import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.notifications.Listener; import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged; import org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged;
import org.infinispan.notifications.cachemanagerlistener.event.ViewChangedEvent; import org.infinispan.notifications.cachemanagerlistener.event.ViewChangedEvent;
import org.infinispan.persistence.remote.RemoteStore; import org.infinispan.persistence.remote.RemoteStore;
import org.infinispan.remoting.transport.Address; import org.infinispan.remoting.transport.Address;
import org.infinispan.remoting.transport.Transport;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
@ -35,10 +33,10 @@ import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory; import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.connections.infinispan.InfinispanUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
@ -47,7 +45,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -72,7 +69,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
// Just to extract notifications related stuff to separate class // Just to extract notifications related stuff to separate class
private InfinispanNotificationsManager notificationsManager; private InfinispanNotificationsManager notificationsManager;
private ExecutorService localExecutor = Executors.newCachedThreadPool(r -> { private final ExecutorService localExecutor = Executors.newCachedThreadPool(r -> {
Thread thread = Executors.defaultThreadFactory().newThread(r); Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setName(this.getClass().getName() + "-" + thread.getName()); thread.setName(this.getClass().getName() + "-" + thread.getName());
return thread; return thread;
@ -140,7 +137,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
static <V extends Serializable> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) { static <V extends Serializable> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) {
AtomicReference<V> resultRef = new AtomicReference<>(); AtomicReference<V> resultRef = new AtomicReference<>();
Retry.executeWithBackoff((int iteration) -> { Retry.executeWithBackoff(iteration -> {
try { try {
V result; V result;
@ -196,17 +193,14 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
@ViewChanged @ViewChanged
public void viewChanged(ViewChangedEvent event) { public void viewChanged(ViewChangedEvent event) {
final Set<String> removedNodesAddresses = convertAddresses(event.getOldMembers()); Set<String> removedNodesAddresses = convertAddresses(event.getOldMembers());
final Set<String> newAddresses = convertAddresses(event.getNewMembers()); Set<String> newAddresses = convertAddresses(event.getNewMembers());
// Use separate thread to avoid potential deadlock // Use separate thread to avoid potential deadlock
localExecutor.execute(() -> { localExecutor.execute(() -> {
try { try {
EmbeddedCacheManager cacheManager = workCache.getCacheManager();
Transport transport = cacheManager.getTransport();
// Coordinator makes sure that entries for outdated nodes are cleaned up // Coordinator makes sure that entries for outdated nodes are cleaned up
if (transport != null && transport.isCoordinator()) { if (workCache.getCacheManager().isCoordinator()) {
removedNodesAddresses.removeAll(newAddresses); removedNodesAddresses.removeAll(newAddresses);
@ -230,14 +224,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
} }
private Set<String> convertAddresses(Collection<Address> addresses) { private Set<String> convertAddresses(Collection<Address> addresses) {
return addresses.stream().map(new Function<Address, String>() { return addresses.stream().map(Object::toString).collect(Collectors.toSet());
@Override
public String apply(Address address) {
return address.toString();
}
}).collect(Collectors.toSet());
} }
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.connections.infinispan; package org.keycloak.connections.infinispan;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.persistence.manager.PersistenceManager; import org.infinispan.persistence.manager.PersistenceManager;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.health.LoadBalancerCheckProvider; import org.keycloak.health.LoadBalancerCheckProvider;
@ -60,9 +61,7 @@ public class InfinispanMultiSiteLoadBalancerCheckProvider implements LoadBalance
return true; // no need to check other caches return true; // no need to check other caches
} }
PersistenceManager persistenceManager = cache.getAdvancedCache() var persistenceManager = ComponentRegistry.componentOf(cache, PersistenceManager.class);
.getComponentRegistry()
.getComponent(PersistenceManager.class);
if (persistenceManager != null && !persistenceManager.isAvailable()) { if (persistenceManager != null && !persistenceManager.isAvailable()) {
LOG.debugf("PersistenceManager for cache '%s' is down.", cacheName); LOG.debugf("PersistenceManager for cache '%s' is down.", cacheName);

View file

@ -17,11 +17,6 @@
package org.keycloak.connections.infinispan; package org.keycloak.connections.infinispan;
import java.time.Instant;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.ProtocolVersion; import org.infinispan.client.hotrod.ProtocolVersion;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
@ -34,7 +29,7 @@ import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.configuration.global.TransportConfigurationBuilder; import org.infinispan.configuration.global.TransportConfigurationBuilder;
import org.infinispan.eviction.EvictionStrategy; import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionType; import org.infinispan.factories.ComponentRegistry;
import org.infinispan.factories.GlobalComponentRegistry; import org.infinispan.factories.GlobalComponentRegistry;
import org.infinispan.factories.impl.BasicComponentRegistry; import org.infinispan.factories.impl.BasicComponentRegistry;
import org.infinispan.factories.impl.ComponentRef; import org.infinispan.factories.impl.ComponentRef;
@ -48,6 +43,11 @@ import org.jgroups.JChannel;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import java.time.Instant;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -58,12 +58,12 @@ public class InfinispanUtil {
public static final int MAXIMUM_REPLACE_RETRIES = 25; public static final int MAXIMUM_REPLACE_RETRIES = 25;
// See if we have RemoteStore (external JDG) configured for cross-Data-Center scenario // See if we have RemoteStore (external JDG) configured for cross-Data-Center scenario
public static Set<RemoteStore> getRemoteStores(Cache ispnCache) { public static Set<RemoteStore> getRemoteStores(Cache<?, ?> ispnCache) {
return ispnCache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class); return ComponentRegistry.componentOf(ispnCache, PersistenceManager.class).getStores(RemoteStore.class);
} }
public static RemoteCache getRemoteCache(Cache ispnCache) { public static RemoteCache getRemoteCache(Cache<?, ?> ispnCache) {
Set<RemoteStore> remoteStores = getRemoteStores(ispnCache); Set<RemoteStore> remoteStores = getRemoteStores(ispnCache);
if (remoteStores.isEmpty()) { if (remoteStores.isEmpty()) {
return null; return null;
@ -88,10 +88,9 @@ public class InfinispanUtil {
* @param lifespanOrigMs * @param lifespanOrigMs
* @return * @return
*/ */
public static long toHotrodTimeMs(BasicCache ispnCache, long lifespanOrigMs) { public static long toHotrodTimeMs(BasicCache<?, ?> ispnCache, long lifespanOrigMs) {
if (ispnCache instanceof RemoteCache && lifespanOrigMs > 2592000000L) { if (ispnCache instanceof RemoteCache<?, ?> remoteCache && lifespanOrigMs > 2592000000L) {
RemoteCache remoteCache = (RemoteCache) ispnCache; ProtocolVersion protocolVersion = remoteCache.getRemoteCacheContainer().getConfiguration().version();
ProtocolVersion protocolVersion = remoteCache.getRemoteCacheManager().getConfiguration().version();
if (ProtocolVersion.PROTOCOL_VERSION_30.compareTo(protocolVersion) > 0) { if (ProtocolVersion.PROTOCOL_VERSION_30.compareTo(protocolVersion) > 0) {
return Time.currentTimeMillis() + lifespanOrigMs; return Time.currentTimeMillis() + lifespanOrigMs;
} }
@ -103,7 +102,7 @@ public class InfinispanUtil {
private static final Object CHANNEL_INIT_SYNCHRONIZER = new Object(); private static final Object CHANNEL_INIT_SYNCHRONIZER = new Object();
public static void configureTransport(GlobalConfigurationBuilder gcb, String nodeName, String siteName, String jgroupsUdpMcastAddr, public static void configureTransport(GlobalConfigurationBuilder gcb, String nodeName, String siteName, String jgroupsUdpMcastAddr,
String jgroupsConfigPath) { String jgroupsConfigPath) {
if (nodeName == null) { if (nodeName == null) {
gcb.transport().defaultTransport(); gcb.transport().defaultTransport();
} else { } else {
@ -166,9 +165,8 @@ public class InfinispanUtil {
ConfigurationBuilder cb = createCacheConfigurationBuilder(); ConfigurationBuilder cb = createCacheConfigurationBuilder();
cb.memory() cb.memory()
.evictionStrategy(EvictionStrategy.NONE) .whenFull(EvictionStrategy.MANUAL)
.evictionType(EvictionType.COUNT) .maxCount(InfinispanConnectionProvider.ACTION_TOKEN_CACHE_DEFAULT_MAX);
.size(InfinispanConnectionProvider.ACTION_TOKEN_CACHE_DEFAULT_MAX);
cb.expiration() cb.expiration()
.maxIdle(InfinispanConnectionProvider.ACTION_TOKEN_MAX_IDLE_SECONDS, TimeUnit.SECONDS) .maxIdle(InfinispanConnectionProvider.ACTION_TOKEN_MAX_IDLE_SECONDS, TimeUnit.SECONDS)
.wakeUpInterval(InfinispanConnectionProvider.ACTION_TOKEN_WAKE_UP_INTERVAL_SECONDS, TimeUnit.SECONDS); .wakeUpInterval(InfinispanConnectionProvider.ACTION_TOKEN_WAKE_UP_INTERVAL_SECONDS, TimeUnit.SECONDS);
@ -209,7 +207,7 @@ public class InfinispanUtil {
* @return the original component that was replaced * @return the original component that was replaced
*/ */
private static <T> T replaceComponent(EmbeddedCacheManager cacheMgr, Class<T> componentType, T replacementComponent, boolean rewire) { private static <T> T replaceComponent(EmbeddedCacheManager cacheMgr, Class<T> componentType, T replacementComponent, boolean rewire) {
GlobalComponentRegistry cr = cacheMgr.getGlobalComponentRegistry(); GlobalComponentRegistry cr = GlobalComponentRegistry.of(cacheMgr);
BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class); BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class);
ComponentRef<T> old = bcr.getComponent(componentType); ComponentRef<T> old = bcr.getComponent(componentType);
bcr.replaceComponent(componentType.getName(), replacementComponent, true); bcr.replaceComponent(componentType.getName(), replacementComponent, true);

View file

@ -17,12 +17,9 @@
package org.keycloak.connections.infinispan; package org.keycloak.connections.infinispan;
import java.net.InetSocketAddress;
import java.security.SecureRandom;
import java.util.Objects;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.distribution.DistributionManager; import org.infinispan.distribution.DistributionManager;
import org.infinispan.factories.GlobalComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.Address; import org.infinispan.remoting.transport.Address;
import org.infinispan.remoting.transport.LocalModeAddress; import org.infinispan.remoting.transport.LocalModeAddress;
@ -30,12 +27,14 @@ import org.infinispan.remoting.transport.Transport;
import org.infinispan.remoting.transport.jgroups.JGroupsAddress; import org.infinispan.remoting.transport.jgroups.JGroupsAddress;
import org.infinispan.remoting.transport.jgroups.JGroupsTransport; import org.infinispan.remoting.transport.jgroups.JGroupsTransport;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jgroups.Event;
import org.jgroups.JChannel;
import org.jgroups.stack.IpAddress; import org.jgroups.stack.IpAddress;
import org.jgroups.util.NameCache; import org.jgroups.util.NameCache;
import org.keycloak.Config; import org.keycloak.Config;
import java.net.InetSocketAddress;
import java.security.SecureRandom;
import java.util.Objects;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -66,9 +65,9 @@ public class TopologyInfo {
} }
if (!embedded) { if (!embedded) {
Transport transport = cacheManager.getTransport(); var addr = cacheManager.getAddress();
if (transport != null) { if (addr != null) {
nodeName = transport.getAddress().toString(); nodeName = addr.toString();
siteName = cacheManager.getCacheManagerConfiguration().transport().siteId(); siteName = cacheManager.getCacheManagerConfiguration().transport().siteId();
if (siteName == null) { if (siteName == null) {
siteName = config.get("siteName"); siteName = config.get("siteName");
@ -133,7 +132,7 @@ public class TopologyInfo {
/** /**
* True if I am primary owner of the key in case of distributed caches. In case of local caches, always return true * True if I am primary owner of the key in case of distributed caches. In case of local caches, always return true
*/ */
public boolean amIOwner(Cache cache, Object key) { public boolean amIOwner(Cache<?, ?> cache, Object key) {
Address myAddress = cache.getCacheManager().getAddress(); Address myAddress = cache.getCacheManager().getAddress();
Address objectOwnerAddress = getOwnerAddress(cache, key); Address objectOwnerAddress = getOwnerAddress(cache, key);
@ -145,7 +144,7 @@ public class TopologyInfo {
/** /**
* Get route to be used as the identifier for sticky session. Return null if I am not able to find the appropriate route (or in case of local mode) * Get route to be used as the identifier for sticky session. Return null if I am not able to find the appropriate route (or in case of local mode)
*/ */
public String getRouteName(Cache cache, Object key) { public String getRouteName(Cache<?, ?> cache, Object key) {
if (cache.getCacheConfiguration().clustering().cacheMode().isClustered() && isGeneratedNodeName) { if (cache.getCacheConfiguration().clustering().cacheMode().isClustered() && isGeneratedNodeName) {
logger.warn("Clustered configuration used, but node name is not properly set. Make sure to start server with jboss.node.name property identifying cluster node"); logger.warn("Clustered configuration used, but node name is not properly set. Make sure to start server with jboss.node.name property identifying cluster node");
} }
@ -168,11 +167,11 @@ public class TopologyInfo {
// If no logical name exists, create one using physical address // If no logical name exists, create one using physical address
if (name == null) { if (name == null) {
Transport transport = cache.getCacheManager().getTransport(); var transport = GlobalComponentRegistry.componentOf(cache.getCacheManager(), Transport.class);
JChannel jgroupsChannel = ((JGroupsTransport) transport).getChannel(); var channel = ((JGroupsTransport) transport).getChannel();
var ipAddress = (IpAddress) channel.getProtocolStack().getTransport().localPhysicalAddress();
IpAddress ipAddress = (IpAddress) jgroupsChannel.down(new Event(Event.GET_PHYSICAL_ADDRESS, jgroupsAddress)); // Physical address might be null if node is no longer a member of the cluster.
// Physical address might be null if node is no longer a member of the cluster // This seems broken, it is returning the IP/PORT for JGroups!?
InetSocketAddress socketAddress = (ipAddress != null) ? new InetSocketAddress(ipAddress.getIpAddress(), ipAddress.getPort()) : new InetSocketAddress(0); InetSocketAddress socketAddress = (ipAddress != null) ? new InetSocketAddress(ipAddress.getIpAddress(), ipAddress.getPort()) : new InetSocketAddress(0);
name = String.format("%s:%s", socketAddress.getHostString(), socketAddress.getPort()); name = String.format("%s:%s", socketAddress.getHostString(), socketAddress.getPort());
@ -183,21 +182,16 @@ public class TopologyInfo {
} }
private Address getOwnerAddress(Cache cache, Object key) { private Address getOwnerAddress(Cache<?, ?> cache, Object key) {
DistributionManager dist = cache.getAdvancedCache().getDistributionManager(); DistributionManager dist = cache.getAdvancedCache().getDistributionManager();
Address address = (dist != null) && !cache.getCacheConfiguration().clustering().cacheMode().isScattered() ? return dist == null ? cache.getCacheManager().getAddress() : dist.getCacheTopology().getDistribution(key).primary();
dist.getCacheTopology().getDistribution(key).primary() :
cache.getCacheManager().getAddress();
return address;
} }
// See org.wildfly.clustering.server.group.CacheGroup // See org.wildfly.clustering.server.group.CacheGroup
private static org.jgroups.Address toJGroupsAddress(Address address) { private static org.jgroups.Address toJGroupsAddress(Address address) {
if ((address == null) || (address == LocalModeAddress.INSTANCE)) return null; if ((address == null) || (address == LocalModeAddress.INSTANCE)) return null;
if (address instanceof JGroupsAddress) { if (address instanceof JGroupsAddress jgroupsAddress) {
JGroupsAddress jgroupsAddress = (JGroupsAddress) address;
return jgroupsAddress.getJGroupsAddress(); return jgroupsAddress.getJGroupsAddress();
} }
throw new IllegalArgumentException(address.toString()); throw new IllegalArgumentException(address.toString());

View file

@ -202,11 +202,8 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache, InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors, new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
getStalledTimeoutInSeconds(defaultStateTransferTimeout)); getStalledTimeoutInSeconds(defaultStateTransferTimeout));
initializer.initCache();
initializer.loadSessions(); initializer.loadSessions();
} }
}); });
log.debugf("Pre-loading login failures from remote cache '%s' finished", cacheName); log.debugf("Pre-loading login failures from remote cache '%s' finished", cacheName);

View file

@ -399,11 +399,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache, InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors, new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
getStalledTimeoutInSeconds(defaultStateTransferTimeout)); getStalledTimeoutInSeconds(defaultStateTransferTimeout));
initializer.initCache();
initializer.loadSessions(); initializer.loadSessions();
} }
}); });
log.debugf("Pre-loading sessions from remote cache '%s' finished", cacheName); log.debugf("Pre-loading sessions from remote cache '%s' finished", cacheName);

View file

@ -17,15 +17,14 @@
package org.keycloak.models.sessions.infinispan.initializer; package org.keycloak.models.sessions.infinispan.initializer;
import java.io.Serializable;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.context.Flag; import org.infinispan.context.Flag;
import org.infinispan.lifecycle.ComponentStatus; import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.remoting.transport.Transport;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import java.io.Serializable;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -74,21 +73,15 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
} }
protected void saveStateToCache(final InitializerState state) { protected void saveStateToCache(InitializerState state) {
// 3 attempts to send the message (it may fail if some node fails in the meantime) // 3 attempts to send the message (it may fail if some node fails in the meantime)
retry(3, new Runnable() { retry(3, () -> {
// Save this synchronously to ensure all nodes read correct state
@Override // We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
public void run() { BaseCacheInitializer.this.workCache.getAdvancedCache().
withFlags(Flag.IGNORE_RETURN_VALUES, Flag.FORCE_SYNCHRONOUS, Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
// Save this synchronously to ensure all nodes read correct state .put(stateKey, state);
// We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
BaseCacheInitializer.this.workCache.getAdvancedCache().
withFlags(Flag.IGNORE_RETURN_VALUES, Flag.FORCE_SYNCHRONOUS, Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
.put(stateKey, state);
}
}); });
} }

View file

@ -18,7 +18,6 @@
package org.keycloak.models.sessions.infinispan.initializer; package org.keycloak.models.sessions.infinispan.initializer;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.factories.ComponentRegistry;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
@ -26,9 +25,9 @@ import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import java.io.Serializable; import java.io.Serializable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/** /**
* Startup initialization for reading persistent userSessions to be filled into infinispan/memory. * Startup initialization for reading persistent userSessions to be filled into infinispan/memory.
@ -53,18 +52,6 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
} }
public void initCache() {
// due to lazy initialization, this might be called from multiple threads simultaneously, therefore, synchronize
synchronized (workCache) {
final ComponentRegistry cr = this.workCache.getAdvancedCache().getComponentRegistry();
// first check if already set, as Infinispan would otherwise throw a RuntimeException
if (cr.getComponent(KeycloakSessionFactory.class) != sessionFactory) {
cr.registerComponent(sessionFactory, KeycloakSessionFactory.class);
}
}
}
// Just coordinator will run this // Just coordinator will run this
@Override @Override
protected void startLoading() { protected void startLoading() {
@ -102,7 +89,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
} }
protected void startLoadingImpl(InitializerState state, SessionLoader.LoaderContext loaderCtx) { protected void startLoadingImpl(InitializerState state, SessionLoader.LoaderContext loaderCtx) {
int errors = 0; final int errors = 0;
int segmentToLoad = 0; int segmentToLoad = 0;
int distributedWorkersCount = 1; int distributedWorkersCount = 1;
@ -117,7 +104,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
log.trace("unfinished segments for this iteration: " + segments); log.trace("unfinished segments for this iteration: " + segments);
} }
final Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>(); Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>();
for (Integer segment : segments) { for (Integer segment : segments) {
SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(segment); SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(segment);

View file

@ -17,11 +17,6 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.Flag; import org.infinispan.client.hotrod.Flag;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
@ -31,12 +26,17 @@ import org.infinispan.client.hotrod.annotation.ClientListener;
import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent; import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent;
import org.infinispan.client.hotrod.event.ClientCacheEntryModifiedEvent; import org.infinispan.client.hotrod.event.ClientCacheEntryModifiedEvent;
import org.infinispan.client.hotrod.exceptions.HotRodClientException; import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager; import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore; import org.infinispan.persistence.remote.RemoteStore;
import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationBuilder; import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationBuilder;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Test concurrency for remoteStore (backed by HotRod RemoteCaches) against external JDG. Especially tests "putIfAbsent" contract. * Test concurrency for remoteStore (backed by HotRod RemoteCaches) against external JDG. Especially tests "putIfAbsent" contract.
* *
@ -46,11 +46,7 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
*/ */
public class ConcurrencyJDGCachePutTest { public class ConcurrencyJDGCachePutTest {
private static Map<String, EntryInfo> state = new HashMap<>(); private static final Map<String, EntryInfo> state = new HashMap<>();
private RemoteCache remoteCache1;
private RemoteCache remoteCache2;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// Init map somehow // Init map somehow
@ -105,7 +101,8 @@ public class ConcurrencyJDGCachePutTest {
System.out.println("Retrieved cache: " + threadId); System.out.println("Retrieved cache: " + threadId);
RemoteStore remoteStore = cache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class).iterator().next(); RemoteStore<?, ?> remoteStore = ComponentRegistry.componentOf(cache, PersistenceManager.class)
.getStores(RemoteStore.class).iterator().next();
HotRodListener listener = new HotRodListener(); HotRodListener listener = new HotRodListener();
remoteStore.getRemoteCache().addClientListener(listener); remoteStore.getRemoteCache().addClientListener(listener);
@ -119,14 +116,14 @@ public class ConcurrencyJDGCachePutTest {
//private AtomicInteger listenerCount = new AtomicInteger(0); //private AtomicInteger listenerCount = new AtomicInteger(0);
@ClientCacheEntryCreated @ClientCacheEntryCreated
public void created(ClientCacheEntryCreatedEvent event) { public void created(ClientCacheEntryCreatedEvent<String> event) {
String cacheKey = (String) event.getKey(); String cacheKey = event.getKey();
state.get(cacheKey).successfulListenerWrites.incrementAndGet(); state.get(cacheKey).successfulListenerWrites.incrementAndGet();
} }
@ClientCacheEntryModified @ClientCacheEntryModified
public void updated(ClientCacheEntryModifiedEvent event) { public void updated(ClientCacheEntryModifiedEvent<String> event) {
String cacheKey = (String) event.getKey(); String cacheKey = event.getKey();
state.get(cacheKey).successfulListenerWrites.incrementAndGet(); state.get(cacheKey).successfulListenerWrites.incrementAndGet();
} }
@ -171,7 +168,10 @@ public class ConcurrencyJDGCachePutTest {
//Integer existingClusterStartTime = (Integer) cache.putIfAbsent(cacheKey, startupTime); //Integer existingClusterStartTime = (Integer) cache.putIfAbsent(cacheKey, startupTime);
// Concurrency works fine with this // Concurrency works fine with this
RemoteCache remoteCache = cache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class).iterator().next().getRemoteCache(); RemoteCache remoteCache = ComponentRegistry.componentOf(cache, PersistenceManager.class)
.getStores(RemoteStore.class)
.iterator().next()
.getRemoteCache();
Integer existingClusterStartTime = null; Integer existingClusterStartTime = null;
for (int i=0 ; i<10 ; i++) { for (int i=0 ; i<10 ; i++) {

View file

@ -17,12 +17,6 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.VersionedValue; import org.infinispan.client.hotrod.VersionedValue;
@ -31,6 +25,7 @@ import org.infinispan.client.hotrod.annotation.ClientCacheEntryModified;
import org.infinispan.client.hotrod.annotation.ClientListener; import org.infinispan.client.hotrod.annotation.ClientListener;
import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent; import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent;
import org.infinispan.client.hotrod.event.ClientCacheEntryModifiedEvent; import org.infinispan.client.hotrod.event.ClientCacheEntryModifiedEvent;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager; import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore; import org.infinispan.persistence.remote.RemoteStore;
@ -39,6 +34,12 @@ import org.junit.Assert;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil; import org.keycloak.connections.infinispan.InfinispanUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Test that hotrod ClientListeners are correctly executed as expected * Test that hotrod ClientListeners are correctly executed as expected
* *
@ -68,11 +69,11 @@ import org.keycloak.connections.infinispan.InfinispanUtil;
public class ConcurrencyJDGRemoteCacheClientListenersTest { public class ConcurrencyJDGRemoteCacheClientListenersTest {
// Helper map to track if listeners were executed // Helper map to track if listeners were executed
private static Map<String, EntryInfo> state = new HashMap<>(); private static final Map<String, EntryInfo> state = new HashMap<>();
private static AtomicInteger totalListenerCalls = new AtomicInteger(0); private static final AtomicInteger totalListenerCalls = new AtomicInteger(0);
private static AtomicInteger totalErrors = new AtomicInteger(0); private static final AtomicInteger totalErrors = new AtomicInteger(0);
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
@ -134,7 +135,8 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest {
System.out.println("Retrieved cache: " + threadId); System.out.println("Retrieved cache: " + threadId);
RemoteStore remoteStore = cache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class).iterator().next(); RemoteStore<?, ?> remoteStore = ComponentRegistry.componentOf(cache, PersistenceManager.class)
.getStores(RemoteStore.class).iterator().next();
HotRodListener listener = new HotRodListener(cache, threadId); HotRodListener listener = new HotRodListener(cache, threadId);
remoteStore.getRemoteCache().addClientListener(listener); remoteStore.getRemoteCache().addClientListener(listener);
@ -147,7 +149,7 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest {
private final RemoteCache<String, Integer> remoteCache; private final RemoteCache<String, Integer> remoteCache;
private final int threadId; private final int threadId;
private Executor executor; private final Executor executor;
public HotRodListener(Cache<String, Integer> cache, int threadId) { public HotRodListener(Cache<String, Integer> cache, int threadId) {
this.remoteCache = InfinispanUtil.getRemoteCache(cache); this.remoteCache = InfinispanUtil.getRemoteCache(cache);
@ -158,26 +160,15 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest {
//private AtomicInteger listenerCount = new AtomicInteger(0); //private AtomicInteger listenerCount = new AtomicInteger(0);
@ClientCacheEntryCreated @ClientCacheEntryCreated
public void created(ClientCacheEntryCreatedEvent event) { public void created(ClientCacheEntryCreatedEvent<String> event) {
String cacheKey = (String) event.getKey(); executor.execute(() -> event(event.getKey(), event.getVersion(), true));
executor.execute(() -> {
event(cacheKey, event.getVersion(), true);
});
} }
@ClientCacheEntryModified @ClientCacheEntryModified
public void updated(ClientCacheEntryModifiedEvent event) { public void updated(ClientCacheEntryModifiedEvent<String> event) {
String cacheKey = (String) event.getKey(); executor.execute(() -> event(event.getKey(), event.getVersion(), false));
executor.execute(() -> {
event(cacheKey, event.getVersion(), false);
});
} }

View file

@ -17,19 +17,11 @@
package org.keycloak.keys.infinispan; package org.keycloak.keys.infinispan;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.configuration.cache.Configuration; import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.eviction.EvictionStrategy; import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionType;
import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.DefaultCacheManager;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
@ -40,12 +32,19 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.crypto.PublicKeysWrapper; import org.keycloak.crypto.PublicKeysWrapper;
import org.keycloak.keys.PublicKeyLoader; import org.keycloak.keys.PublicKeyLoader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class InfinispanKeyStorageProviderTest { public class InfinispanKeyStorageProviderTest {
private Map<String, AtomicInteger> counters = new ConcurrentHashMap<>(); private final Map<String, AtomicInteger> counters = new ConcurrentHashMap<>();
Cache<String, PublicKeysEntry> keys = getKeysCache(); Cache<String, PublicKeysEntry> keys = getKeysCache();
Map<String, FutureTask<PublicKeysEntry>> tasksInProgress = new ConcurrentHashMap<>(); Map<String, FutureTask<PublicKeysEntry>> tasksInProgress = new ConcurrentHashMap<>();
@ -157,14 +156,13 @@ public class InfinispanKeyStorageProviderTest {
protected Cache<String, PublicKeysEntry> getKeysCache() { protected Cache<String, PublicKeysEntry> getKeysCache() {
GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder(); GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
gcb.jmx().domain(InfinispanConnectionProvider.JMX_DOMAIN).enable(); gcb.jmx().domain(InfinispanConnectionProvider.JMX_DOMAIN).enable();
final DefaultCacheManager cacheManager = new DefaultCacheManager(gcb.build()); DefaultCacheManager cacheManager = new DefaultCacheManager(gcb.build());
ConfigurationBuilder cb = new ConfigurationBuilder(); ConfigurationBuilder cb = new ConfigurationBuilder();
cb.memory() cb.memory()
.evictionStrategy(EvictionStrategy.REMOVE) .whenFull(EvictionStrategy.REMOVE)
.evictionType(EvictionType.COUNT) .maxCount(InfinispanConnectionProvider.KEYS_CACHE_DEFAULT_MAX);
.size(InfinispanConnectionProvider.KEYS_CACHE_DEFAULT_MAX); cb.statistics().enabled(true);
cb.jmxStatistics().enabled(true);
Configuration cfg = cb.build(); Configuration cfg = cb.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.KEYS_CACHE_NAME, cfg); cacheManager.defineConfiguration(InfinispanConnectionProvider.KEYS_CACHE_NAME, cfg);

View file

@ -18,8 +18,8 @@
<infinispan <infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd" xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd"
xmlns="urn:infinispan:config:14.0"> xmlns="urn:infinispan:config:15.0">
<cache-container name="keycloak"> <cache-container name="keycloak">
<transport lock-timeout="60000"/> <transport lock-timeout="60000"/>

38
pom.xml
View file

@ -93,7 +93,7 @@
<h2.version>2.2.224</h2.version> <h2.version>2.2.224</h2.version>
<hibernate-orm.plugin.version>6.2.13.Final</hibernate-orm.plugin.version> <hibernate-orm.plugin.version>6.2.13.Final</hibernate-orm.plugin.version>
<hibernate.c3p0.version>6.2.13.Final</hibernate.c3p0.version> <hibernate.c3p0.version>6.2.13.Final</hibernate.c3p0.version>
<infinispan.version>14.0.27.Final</infinispan.version> <infinispan.version>15.0.3.Final</infinispan.version>
<!--JAKARTA--> <!--JAKARTA-->
<jakarta.mail.version>2.1.1</jakarta.mail.version> <jakarta.mail.version>2.1.1</jakarta.mail.version>
@ -311,42 +311,6 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-jboss-marshalling</artifactId>
<version>${infinispan.version}</version>
<exclusions>
<!-- this conflicts with infinispan-*-jakarta -->
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId>
<version>${infinispan.version}</version>
<exclusions>
<!-- this conflicts with infinispan-*-jakarta -->
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons</artifactId>
</exclusion>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>io.quarkus.platform</groupId> <groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId> <artifactId>quarkus-bom</artifactId>

View file

@ -38,7 +38,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-commons-jakarta</artifactId> <artifactId>infinispan-commons</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>

View file

@ -457,19 +457,9 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId> <artifactId>infinispan-cachestore-remote</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.ua-parser</groupId> <groupId>com.github.ua-parser</groupId>
@ -558,11 +548,11 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-commons-jakarta</artifactId> <artifactId>infinispan-commons</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>

View file

@ -18,8 +18,8 @@
<infinispan <infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd" xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd"
xmlns="urn:infinispan:config:14.0"> xmlns="urn:infinispan:config:15.0">
<cache-container name="keycloak"> <cache-container name="keycloak">
<transport lock-timeout="60000"/> <transport lock-timeout="60000"/>

View file

@ -18,8 +18,8 @@
<infinispan <infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd" xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd"
xmlns="urn:infinispan:config:14.0"> xmlns="urn:infinispan:config:15.0">
<cache-container name="keycloak"> <cache-container name="keycloak">
<local-cache name="default"> <local-cache name="default">

View file

@ -21,9 +21,9 @@
<!--tag::keycloak-ispn-configmap[] --> <!--tag::keycloak-ispn-configmap[] -->
<infinispan <infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 https://www.infinispan.org/schemas/infinispan-config-14.0.xsd xsi:schemaLocation="urn:infinispan:config:15.0 https://www.infinispan.org/schemas/infinispan-config-15.0.xsd
urn:infinispan:config:store:remote:14.0 https://www.infinispan.org/schemas/infinispan-cachestore-remote-config-14.0.xsd" urn:infinispan:config:store:remote:15.0 https://www.infinispan.org/schemas/infinispan-cachestore-remote-config-15.0.xsd"
xmlns="urn:infinispan:config:14.0"> xmlns="urn:infinispan:config:15.0">
<!--end::keycloak-ispn-configmap[] --> <!--end::keycloak-ispn-configmap[] -->
<!-- the statistics="true" attribute is not part of the original KC config and was added by Keycloak Benchmark --> <!-- the statistics="true" attribute is not part of the original KC config and was added by Keycloak Benchmark -->
@ -47,8 +47,8 @@
<!--tag::keycloak-ispn-remotestore[] --> <!--tag::keycloak-ispn-remotestore[] -->
<distributed-cache name="sessions" owners="2" statistics="true"> <distributed-cache name="sessions" owners="2" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <!--1--> <persistence passivation="false" availability-interval="500"> <!--1-->
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="sessions" cache="sessions"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -71,8 +71,8 @@
<!--end::keycloak-ispn-remotestore[] --> <!--end::keycloak-ispn-remotestore[] -->
<distributed-cache name="authenticationSessions" owners="2" statistics="true"> <distributed-cache name="authenticationSessions" owners="2" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="authenticationSessions" cache="authenticationSessions"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -94,8 +94,8 @@
</distributed-cache> </distributed-cache>
<distributed-cache name="offlineSessions" owners="2" statistics="true"> <distributed-cache name="offlineSessions" owners="2" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="offlineSessions" cache="offlineSessions"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -117,8 +117,8 @@
</distributed-cache> </distributed-cache>
<distributed-cache name="clientSessions" owners="2" statistics="true"> <distributed-cache name="clientSessions" owners="2" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="clientSessions" cache="clientSessions"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -140,8 +140,8 @@
</distributed-cache> </distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2" statistics="true"> <distributed-cache name="offlineClientSessions" owners="2" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="offlineClientSessions" cache="offlineClientSessions"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -163,8 +163,8 @@
</distributed-cache> </distributed-cache>
<distributed-cache name="loginFailures" owners="2" statistics="true"> <distributed-cache name="loginFailures" owners="2" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="loginFailures" cache="loginFailures"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -193,8 +193,8 @@
</local-cache> </local-cache>
<replicated-cache name="work" statistics="true"> <replicated-cache name="work" statistics="true">
<expiration lifespan="-1"/> <expiration lifespan="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="work" cache="work"
raw-values="true" raw-values="true"
shared="true" shared="true"
@ -229,8 +229,8 @@
</encoding> </encoding>
<expiration max-idle="-1" lifespan="-1" interval="300000"/> <expiration max-idle="-1" lifespan="-1" interval="300000"/>
<memory max-count="-1"/> <memory max-count="-1"/>
<persistence passivation="false"> <persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0" <remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="actionTokens" cache="actionTokens"
raw-values="true" raw-values="true"
shared="true" shared="true"

View file

@ -86,21 +86,11 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-tasks-api</artifactId> <artifactId>infinispan-tasks-api</artifactId>
<exclusions>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>

View file

@ -48,14 +48,14 @@ public class InfinispanTimeServiceTask implements ServerTask<String> {
@Override @Override
public String call() { public String call() {
EmbeddedCacheManager cacheManager = context.getCacheManager(); EmbeddedCacheManager cacheManager = context.getCacheManager();
Map<String, Object> params = new HashMap(); Map<String, Object> params = new HashMap<>();
if (this.context.getParameters().isPresent()) if (this.context.getParameters().isPresent())
params = this.context.getParameters().get(); params = this.context.getParameters().get();
if (params.containsKey("timeService")) { if (params.containsKey("timeService")) {
offset = (int) params.get("timeService"); offset = (int) params.get("timeService");
// rewire the Time service // rewire the Time service
GlobalComponentRegistry cr = cacheManager.getGlobalComponentRegistry(); GlobalComponentRegistry cr = GlobalComponentRegistry.of(cacheManager);
BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class); BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class);
bcr.replaceComponent(TimeService.class.getName(), KEYCLOAK_TIME_SERVICE, true); bcr.replaceComponent(TimeService.class.getName(), KEYCLOAK_TIME_SERVICE, true);
cr.rewire(); cr.rewire();

View file

@ -17,29 +17,28 @@
package org.keycloak.testsuite.rest.resource; package org.keycloak.testsuite.rest.resource;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.stream.CacheCollectors;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity; import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.utils.MediaType; import org.keycloak.utils.MediaType;
import org.infinispan.stream.CacheCollectors;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -114,12 +113,10 @@ public class TestCacheResource {
@Path("/remote-cache-stats") @Path("/remote-cache-stats")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, String> getRemoteCacheStats() { public Map<String, String> getRemoteCacheStats() {
RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache); var remoteCache = InfinispanUtil.getRemoteCache(cache);
if (remoteCache == null) { return remoteCache == null ?
return new HashMap<>(); Collections.emptyMap() :
} else { remoteCache.serverStatistics().getStatsMap();
return remoteCache.stats().getStatsMap();
}
} }
@ -127,11 +124,11 @@ public class TestCacheResource {
@Path("/remote-cache-last-session-refresh/{user-session-id}") @Path("/remote-cache-last-session-refresh/{user-session-id}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public int getRemoteCacheLastSessionRefresh(@PathParam("user-session-id") String userSessionId) { public int getRemoteCacheLastSessionRefresh(@PathParam("user-session-id") String userSessionId) {
RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache); RemoteCache<String, SessionEntityWrapper<UserSessionEntity>> remoteCache = InfinispanUtil.getRemoteCache(cache);
if (remoteCache == null) { if (remoteCache == null) {
return -1; return -1;
} else { } else {
SessionEntityWrapper<UserSessionEntity> userSession = (SessionEntityWrapper<UserSessionEntity>) remoteCache.get(userSessionId); SessionEntityWrapper<UserSessionEntity> userSession = remoteCache.get(userSessionId);
if (userSession == null) { if (userSession == null) {
return -1; return -1;
} else { } else {

View file

@ -151,7 +151,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-server-hotrod-jakarta</artifactId> <artifactId>infinispan-server-hotrod</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>

View file

@ -1819,7 +1819,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -104,7 +104,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>

View file

@ -227,7 +227,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId> <artifactId>infinispan-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>