diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java
index 73ab3fe4c3..c5417c2cbc 100644
--- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java
@@ -19,6 +19,7 @@ package org.keycloak.cluster.infinispan;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
+import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged;
@@ -230,7 +231,11 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory,
Tracked in https://github.com/keycloak/keycloak/issues/9871
*/
synchronized (DefaultInfinispanConnectionProviderFactory.class) {
- workCache.entrySet().removeIf(new LockEntryPredicate(removedNodesAddresses));
+ if (workCache.getStatus() == ComponentStatus.RUNNING) {
+ workCache.entrySet().removeIf(new LockEntryPredicate(removedNodesAddresses));
+ } else {
+ logger.warn("work cache is not running, ignoring event");
+ }
}
}
} catch (Throwable t) {
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index b9f543aff0..35c78f0acd 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -66,17 +66,17 @@ import static org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderF
*/
public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory, EnvironmentDependentProviderFactory {
- protected static final Logger logger = Logger.getLogger(DefaultInfinispanConnectionProviderFactory.class);
+ private static final Logger logger = Logger.getLogger(DefaultInfinispanConnectionProviderFactory.class);
- protected Config.Scope config;
+ private Config.Scope config;
- protected EmbeddedCacheManager cacheManager;
+ private volatile EmbeddedCacheManager cacheManager;
- protected RemoteCacheProvider remoteCacheProvider;
+ private volatile RemoteCacheProvider remoteCacheProvider;
- protected boolean containerManaged;
+ protected volatile boolean containerManaged;
- private TopologyInfo topologyInfo;
+ private volatile TopologyInfo topologyInfo;
@Override
public InfinispanConnectionProvider create(KeycloakSession session) {
@@ -102,7 +102,6 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (remoteCacheProvider != null) {
remoteCacheProvider.stop();
}
- cacheManager = null;
}
}
@@ -142,62 +141,67 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
managedCacheManager = provider.getCacheManager(config);
}
-
+
+ // store it in a locale variable first, so it is not visible to the outside, yet
+ EmbeddedCacheManager localCacheManager;
if (managedCacheManager == null) {
if (!config.getBoolean("embedded", false)) {
throw new RuntimeException("No " + ManagedCacheManagerProvider.class.getName() + " found. If running in embedded mode set the [embedded] property to this provider.");
}
- initEmbedded();
+ localCacheManager = initEmbedded();
} else {
- initContainerManaged(managedCacheManager);
+ localCacheManager = initContainerManaged(managedCacheManager);
}
logger.infof(topologyInfo.toString());
- remoteCacheProvider = new RemoteCacheProvider(config, cacheManager);
+ remoteCacheProvider = new RemoteCacheProvider(config, localCacheManager);
+ // only set the cache manager attribute at the very end to avoid passing a half-initialized entry callers
+ cacheManager = localCacheManager;
}
}
}
}
- protected void initContainerManaged(EmbeddedCacheManager cacheManager) {
- this.cacheManager = cacheManager;
+ protected EmbeddedCacheManager initContainerManaged(EmbeddedCacheManager cacheManager) {
containerManaged = true;
- long realmRevisionsMaxEntries = this.cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME).getCacheConfiguration().memory().size();
+ long realmRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME).getCacheConfiguration().memory().size();
realmRevisionsMaxEntries = realmRevisionsMaxEntries > 0
? 2 * realmRevisionsMaxEntries
: InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX;
- this.cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(realmRevisionsMaxEntries));
- this.cacheManager.getCache(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, true);
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(realmRevisionsMaxEntries));
+ cacheManager.getCache(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, true);
- long userRevisionsMaxEntries = this.cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().memory().size();
+ long userRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().memory().size();
userRevisionsMaxEntries = userRevisionsMaxEntries > 0
? 2 * userRevisionsMaxEntries
: InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX;
- this.cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(userRevisionsMaxEntries));
- this.cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
- this.cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
- this.cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
- this.cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
- this.cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(userRevisionsMaxEntries));
+ cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
+ cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
+ cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
+ cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
+ cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
- long authzRevisionsMaxEntries = this.cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().memory().size();
+ long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().memory().size();
authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
? 2 * authzRevisionsMaxEntries
: InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
- this.cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
- this.cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
+ cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
- this.topologyInfo = new TopologyInfo(this.cacheManager, config, false);
+ this.topologyInfo = new TopologyInfo(cacheManager, config, false);
logger.debugv("Using container managed Infinispan cache container, lookup={0}", cacheManager);
+
+ return cacheManager;
}
- protected void initEmbedded() {
+ protected EmbeddedCacheManager initEmbedded() {
GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
boolean clustered = config.getBoolean("clustered", false);
@@ -221,7 +225,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
// See https://infinispan.org/docs/stable/titles/developing/developing.html#marshalling for the details
gcb.serialization().marshaller(new JBossUserMarshaller());
- cacheManager = new DefaultCacheManager(gcb.build());
+ EmbeddedCacheManager cacheManager = new DefaultCacheManager(gcb.build());
if (useKeycloakTimeService) {
setTimeServiceToKeycloakTime(cacheManager);
}
@@ -374,6 +378,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
+
+ return cacheManager;
}
private Configuration getRevisionCacheConfig(long maxEntries) {
diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/LegacyInfinispanConnectionFactory.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/LegacyInfinispanConnectionFactory.java
index c1a86a32a4..f8f0b42250 100644
--- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/LegacyInfinispanConnectionFactory.java
+++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/LegacyInfinispanConnectionFactory.java
@@ -29,11 +29,12 @@ public class LegacyInfinispanConnectionFactory extends DefaultInfinispanConnecti
implements EnvironmentDependentProviderFactory {
@Override
- protected void initContainerManaged(EmbeddedCacheManager cacheManager) {
- super.initContainerManaged(cacheManager);
+ protected EmbeddedCacheManager initContainerManaged(EmbeddedCacheManager cacheManager) {
+ EmbeddedCacheManager result = super.initContainerManaged(cacheManager);
// force closing the cache manager when stopping the provider
// we probably want to refactor the default impl a bit to support this use case
containerManaged = false;
+ return result;
}
@Override
diff --git a/testsuite/model/pom.xml b/testsuite/model/pom.xml
index f866f1b541..184b69270a 100644
--- a/testsuite/model/pom.xml
+++ b/testsuite/model/pom.xml
@@ -148,6 +148,8 @@
@{argLine} -Xmx1536m -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
+
+ 1
${keycloak.model.parameters}
diff --git a/testsuite/model/src/main/java/org/keycloak/testsuite/model/Config.java b/testsuite/model/src/main/java/org/keycloak/testsuite/model/Config.java
index b65713f8fe..a034cac90f 100644
--- a/testsuite/model/src/main/java/org/keycloak/testsuite/model/Config.java
+++ b/testsuite/model/src/main/java/org/keycloak/testsuite/model/Config.java
@@ -24,6 +24,7 @@ import org.keycloak.common.util.SystemEnvProperties;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
@@ -35,7 +36,7 @@ public class Config implements ConfigProvider {
private final Properties systemProperties = new SystemEnvProperties();
- private final Map defaultProperties = new HashMap<>();
+ private final Map defaultProperties = new ConcurrentHashMap<>();
private final ThreadLocal