Avoid reseting cachemanger to null to avoid a re-initialization (#24086)
Also follow best practices of using volatile variables for double-locking, and not using shutdown caches. Closes #24085
This commit is contained in:
parent
565bc7d664
commit
26e2fde115
5 changed files with 48 additions and 33 deletions
|
@ -19,6 +19,7 @@ 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.manager.EmbeddedCacheManager;
|
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;
|
||||||
|
@ -230,7 +231,11 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory,
|
||||||
Tracked in https://github.com/keycloak/keycloak/issues/9871
|
Tracked in https://github.com/keycloak/keycloak/issues/9871
|
||||||
*/
|
*/
|
||||||
synchronized (DefaultInfinispanConnectionProviderFactory.class) {
|
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) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -66,17 +66,17 @@ import static org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderF
|
||||||
*/
|
*/
|
||||||
public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory, EnvironmentDependentProviderFactory {
|
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
|
@Override
|
||||||
public InfinispanConnectionProvider create(KeycloakSession session) {
|
public InfinispanConnectionProvider create(KeycloakSession session) {
|
||||||
|
@ -102,7 +102,6 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
|
||||||
if (remoteCacheProvider != null) {
|
if (remoteCacheProvider != null) {
|
||||||
remoteCacheProvider.stop();
|
remoteCacheProvider.stop();
|
||||||
}
|
}
|
||||||
cacheManager = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,61 +142,66 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
|
||||||
managedCacheManager = provider.getCacheManager(config);
|
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 (managedCacheManager == null) {
|
||||||
if (!config.getBoolean("embedded", false)) {
|
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.");
|
throw new RuntimeException("No " + ManagedCacheManagerProvider.class.getName() + " found. If running in embedded mode set the [embedded] property to this provider.");
|
||||||
}
|
}
|
||||||
initEmbedded();
|
localCacheManager = initEmbedded();
|
||||||
} else {
|
} else {
|
||||||
initContainerManaged(managedCacheManager);
|
localCacheManager = initContainerManaged(managedCacheManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.infof(topologyInfo.toString());
|
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) {
|
protected EmbeddedCacheManager initContainerManaged(EmbeddedCacheManager cacheManager) {
|
||||||
this.cacheManager = cacheManager;
|
|
||||||
containerManaged = true;
|
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
|
realmRevisionsMaxEntries = realmRevisionsMaxEntries > 0
|
||||||
? 2 * realmRevisionsMaxEntries
|
? 2 * realmRevisionsMaxEntries
|
||||||
: InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX;
|
: InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX;
|
||||||
|
|
||||||
this.cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(realmRevisionsMaxEntries));
|
cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(realmRevisionsMaxEntries));
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, true);
|
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
|
userRevisionsMaxEntries = userRevisionsMaxEntries > 0
|
||||||
? 2 * userRevisionsMaxEntries
|
? 2 * userRevisionsMaxEntries
|
||||||
: InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX;
|
: InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX;
|
||||||
|
|
||||||
this.cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(userRevisionsMaxEntries));
|
cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(userRevisionsMaxEntries));
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
|
cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
|
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
|
cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
|
cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, 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
|
authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
|
||||||
? 2 * authzRevisionsMaxEntries
|
? 2 * authzRevisionsMaxEntries
|
||||||
: InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
|
: InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
|
||||||
|
|
||||||
this.cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
|
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
|
||||||
this.cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
|
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);
|
logger.debugv("Using container managed Infinispan cache container, lookup={0}", cacheManager);
|
||||||
|
|
||||||
|
return cacheManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initEmbedded() {
|
protected EmbeddedCacheManager initEmbedded() {
|
||||||
GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
|
GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
|
||||||
|
|
||||||
boolean clustered = config.getBoolean("clustered", false);
|
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
|
// See https://infinispan.org/docs/stable/titles/developing/developing.html#marshalling for the details
|
||||||
gcb.serialization().marshaller(new JBossUserMarshaller());
|
gcb.serialization().marshaller(new JBossUserMarshaller());
|
||||||
|
|
||||||
cacheManager = new DefaultCacheManager(gcb.build());
|
EmbeddedCacheManager cacheManager = new DefaultCacheManager(gcb.build());
|
||||||
if (useKeycloakTimeService) {
|
if (useKeycloakTimeService) {
|
||||||
setTimeServiceToKeycloakTime(cacheManager);
|
setTimeServiceToKeycloakTime(cacheManager);
|
||||||
}
|
}
|
||||||
|
@ -374,6 +378,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
|
||||||
|
|
||||||
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
|
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
|
||||||
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
|
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
|
||||||
|
|
||||||
|
return cacheManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Configuration getRevisionCacheConfig(long maxEntries) {
|
private Configuration getRevisionCacheConfig(long maxEntries) {
|
||||||
|
|
|
@ -29,11 +29,12 @@ public class LegacyInfinispanConnectionFactory extends DefaultInfinispanConnecti
|
||||||
implements EnvironmentDependentProviderFactory {
|
implements EnvironmentDependentProviderFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initContainerManaged(EmbeddedCacheManager cacheManager) {
|
protected EmbeddedCacheManager initContainerManaged(EmbeddedCacheManager cacheManager) {
|
||||||
super.initContainerManaged(cacheManager);
|
EmbeddedCacheManager result = super.initContainerManaged(cacheManager);
|
||||||
// force closing the cache manager when stopping the provider
|
// force closing the cache manager when stopping the provider
|
||||||
// we probably want to refactor the default impl a bit to support this use case
|
// we probably want to refactor the default impl a bit to support this use case
|
||||||
containerManaged = false;
|
containerManaged = false;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -148,6 +148,8 @@
|
||||||
<!-- See also https://github.com/wildfly/wildfly-core/blob/7e5624cf92ebe4b64a4793a8c0b2a340c0d6d363/core-feature-pack/common/src/main/resources/content/bin/common.sh#L57-L60 -->
|
<!-- See also https://github.com/wildfly/wildfly-core/blob/7e5624cf92ebe4b64a4793a8c0b2a340c0d6d363/core-feature-pack/common/src/main/resources/content/bin/common.sh#L57-L60 -->
|
||||||
<argLine>@{argLine} -Xmx1536m -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED</argLine>
|
<argLine>@{argLine} -Xmx1536m -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED</argLine>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
|
<!-- ensure a log entry if we're running out of JGroup threads -->
|
||||||
|
<jgroups.thread_dumps_threshold>1</jgroups.thread_dumps_threshold>
|
||||||
<!-- keycloak.model.parameters lists parameter classes from
|
<!-- keycloak.model.parameters lists parameter classes from
|
||||||
org.keycloak.model.parameters package and determine enabled providers -->
|
org.keycloak.model.parameters package and determine enabled providers -->
|
||||||
<keycloak.model.parameters>${keycloak.model.parameters}</keycloak.model.parameters>
|
<keycloak.model.parameters>${keycloak.model.parameters}</keycloak.model.parameters>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.keycloak.common.util.SystemEnvProperties;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ public class Config implements ConfigProvider {
|
||||||
|
|
||||||
private final Properties systemProperties = new SystemEnvProperties();
|
private final Properties systemProperties = new SystemEnvProperties();
|
||||||
|
|
||||||
private final Map<String, String> defaultProperties = new HashMap<>();
|
private final Map<String, String> defaultProperties = new ConcurrentHashMap<>();
|
||||||
private final ThreadLocal<Map<String, String>> properties = new ThreadLocal<Map<String, String>>() {
|
private final ThreadLocal<Map<String, String>> properties = new ThreadLocal<Map<String, String>>() {
|
||||||
@Override
|
@Override
|
||||||
protected Map<String, String> initialValue() {
|
protected Map<String, String> initialValue() {
|
||||||
|
|
Loading…
Reference in a new issue