Remove Infinispan workarounds after upgrading to 13.x

Closes #13962
This commit is contained in:
Alexander Schwartz 2022-08-26 12:05:38 +02:00 committed by Pedro Igor
parent 3f088bfd21
commit bb6b5abfa1
4 changed files with 35 additions and 104 deletions

View file

@ -221,12 +221,14 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory,
}
logger.debugf("Nodes %s removed from cluster. Removing tasks locked by this nodes", removedNodesAddresses.toString());
/*
workaround for Infinispan 12.1.7.Final to prevent a deadlock while
DefaultInfinispanConnectionProviderFactory is shutting down PersistenceManagerImpl
that acquires a writeLock and this removal that acquires a readLock.
https://issues.redhat.com/browse/ISPN-13664
*/
/*
workaround for Infinispan 12.1.7.Final to prevent a deadlock while
DefaultInfinispanConnectionProviderFactory is shutting down PersistenceManagerImpl
that acquires a writeLock and this removal that acquires a readLock.
First seen with https://issues.redhat.com/browse/ISPN-13664 and still occurs probably due to
https://issues.redhat.com/browse/ISPN-13666 in 13.0.10
Tracked in https://github.com/keycloak/keycloak/issues/9871
*/
synchronized (DefaultInfinispanConnectionProviderFactory.class) {
workCache.entrySet().removeIf(new LockEntryPredicate(removedNodesAddresses));
}

View file

@ -162,7 +162,9 @@ public class InfinispanNotificationsManager {
workaround for Infinispan 12.1.7.Final to prevent a deadlock while
DefaultInfinispanConnectionProviderFactory is shutting down PersistenceManagerImpl
that acquires a writeLock and this put that acquires a readLock.
https://issues.redhat.com/browse/ISPN-13664
First seen with https://issues.redhat.com/browse/ISPN-13664 and still occurs probably due to
https://issues.redhat.com/browse/ISPN-13666 in 13.0.10
Tracked in https://github.com/keycloak/keycloak/issues/9871
*/
synchronized (DefaultInfinispanConnectionProviderFactory.class) {
workRemoteCache.put(eventKey, wrappedEvent, 120, TimeUnit.SECONDS);
@ -244,7 +246,9 @@ public class InfinispanNotificationsManager {
workaround for Infinispan 12.1.7.Final to prevent a deadlock while
DefaultInfinispanConnectionProviderFactory is shutting down PersistenceManagerImpl
that acquires a writeLock and this get that acquires a readLock.
https://issues.redhat.com/browse/ISPN-13664
First seen with https://issues.redhat.com/browse/ISPN-13664 and still occurs probably due to
https://issues.redhat.com/browse/ISPN-13666 in 13.0.10
Tracked in https://github.com/keycloak/keycloak/issues/9871
*/
Object value;
synchronized (DefaultInfinispanConnectionProviderFactory.class) {

View file

@ -91,7 +91,9 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
workaround for Infinispan 12.1.7.Final to prevent a deadlock while
DefaultInfinispanConnectionProviderFactory is shutting down PersistenceManagerImpl
that acquires a writeLock and this removal that acquires a readLock.
https://issues.redhat.com/browse/ISPN-13664
First seen with https://issues.redhat.com/browse/ISPN-13664 and still occurs probably due to
https://issues.redhat.com/browse/ISPN-13666 in 13.0.10
Tracked in https://github.com/keycloak/keycloak/issues/9871
*/
synchronized (DefaultInfinispanConnectionProviderFactory.class) {
if (cacheManager != null && !containerManaged) {

View file

@ -16,15 +16,12 @@
*/
package org.keycloak.testsuite.model;
import org.infinispan.commons.CacheConfigurationException;
import org.infinispan.manager.EmbeddedCacheManagerStartupException;
import org.junit.Assert;
import org.keycloak.Config.Scope;
import org.keycloak.authorization.AuthorizationSpi;
import org.keycloak.authorization.DefaultAuthorizationProviderFactory;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.policy.provider.PolicySpi;
import org.keycloak.authorization.policy.provider.permission.UMAPolicyProviderFactory;
import org.keycloak.authorization.store.StoreFactorySpi;
import org.keycloak.cluster.ClusterSpi;
import org.keycloak.common.util.Time;
@ -76,11 +73,9 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
@ -282,7 +277,6 @@ public abstract class KeycloakModelTest {
* local to the thread that calls this method, allowing for per-thread customization. This in turn allows
* testing of several parallel session factories which can be used to simulate several servers
* running in parallel.
* @return
*/
public static KeycloakSessionFactory createKeycloakSessionFactory() {
int factoryIndex = FACTORY_COUNT.incrementAndGet();
@ -345,7 +339,7 @@ public abstract class KeycloakModelTest {
/**
* Runs the given {@code task} in {@code numThreads} parallel threads, each thread operating
* in the context of a fresh {@link KeycloakSessionFactory} independent of each other thread.
*
* <p>
* Will throw an exception when the thread throws an exception or if the thread doesn't complete in time.
*
* @see #inIndependentFactory
@ -367,53 +361,27 @@ public abstract class KeycloakModelTest {
}
});
try {
/*
workaround for Infinispan 12.1.7.Final to prevent an internal Infinispan NullPointerException
when multiple nodes tried to join at the same time by starting them sequentially,
although that does not catch 100% of all occurrences.
Already fixed in Infinispan 13.
https://issues.redhat.com/browse/ISPN-13231
*/
Semaphore sem = new Semaphore(1);
CountDownLatch start = new CountDownLatch(numThreads);
CountDownLatch stop = new CountDownLatch(numThreads);
Callable<?> independentTask = () -> {
AtomicBoolean locked = new AtomicBoolean(false);
Callable<?> independentTask = () -> inIndependentFactory(() -> {
// use the latch to ensure that all caches are online while the transaction below runs to avoid a RemoteException
start.countDown();
start.await();
try {
sem.acquire();
locked.set(true);
Object val = inIndependentFactory(() -> {
sem.release();
locked.set(false);
task.run();
// use the latch to ensure that all caches are online while the transaction below runs to avoid a RemoteException
start.countDown();
start.await();
try {
task.run();
// use the latch to ensure that all caches are online while the transaction above runs to avoid a RemoteException
// otherwise might fail with "Cannot wire or start components while the registry is not running" during shutdown
// https://issues.redhat.com/browse/ISPN-9761
} finally {
stop.countDown();
}
stop.await();
sem.acquire();
locked.set(true);
return null;
});
sem.release();
locked.set(false);
return val;
// use the latch to ensure that all caches are online while the transaction above runs to avoid a RemoteException
// otherwise might fail with "Cannot wire or start components while the registry is not running" during shutdown
// https://issues.redhat.com/browse/ISPN-9761
} finally {
if (locked.get()) {
sem.release();
}
stop.countDown();
}
};
stop.await();
return null;
});
// submit tasks, and wait for the results without cancelling execution so that we'll be able to analyze the thread dump
List<? extends Future<?>> tasks = IntStream.range(0, numThreads)
@ -484,53 +452,16 @@ public abstract class KeycloakModelTest {
/**
* Runs the given {@code task} in a context of a fresh {@link KeycloakSessionFactory} which is created before
* running the task and destroyed afterwards.
* @return
*/
public static <T> T inIndependentFactory(Callable<T> task) {
if (USE_DEFAULT_FACTORY) {
throw new IllegalStateException("USE_DEFAULT_FACTORY must be false to use an independent factory");
}
KeycloakSessionFactory original = getFactory();
int retries = 10;
KeycloakSessionFactory factory = null;
do {
try {
factory = createKeycloakSessionFactory();
} catch (CacheConfigurationException | EmbeddedCacheManagerStartupException ex) {
if (retries > 0) {
/*
workaround for Infinispan 12.1.7.Final for a NullPointerException
when multiple nodes tried to join at the same time. Retry until this succeeds.
Already fixed in Infinispan 13.
https://issues.redhat.com/browse/ISPN-13231
*/
LOG.warn("initialization failed, retrying", ex);
--retries;
} else {
throw ex;
}
}
} while (factory == null);
KeycloakSessionFactory factory = createKeycloakSessionFactory();
try {
setFactory(factory);
do {
try {
return task.call();
} catch (CacheConfigurationException | EmbeddedCacheManagerStartupException ex) {
if (retries > 0) {
/*
workaround for Infinispan 12.1.7.Final for a NullPointerException
when multiple nodes tried to join at the same time. Retry until this succeeds.
Already fixed in Infinispan 13.
https://issues.redhat.com/browse/ISPN-13231
*/
LOG.warn("initialization failed, retrying", ex);
-- retries;
} else {
throw ex;
}
}
} while (true);
return task.call();
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
@ -586,10 +517,6 @@ public abstract class KeycloakModelTest {
return MODEL_PARAMETERS.stream().flatMap(mp -> mp.getParameters(clazz)).filter(Objects::nonNull);
}
protected <T> void withEach(Class<T> parameterClazz, Consumer<T> what) {
getParameters(parameterClazz).forEach(what);
}
protected <T> void inRolledBackTransaction(T parameter, BiConsumer<KeycloakSession, T> what) {
KeycloakSession session = getFactory().create();
session.getTransactionManager().begin();
@ -634,10 +561,6 @@ public abstract class KeycloakModelTest {
* Convenience method for {@link #inComittedTransaction(java.util.function.Consumer)} that
* obtains realm model from the session and puts it into session context before
* running the {@code what} task.
* @param <R>
* @param realmId
* @param what
* @return
*/
protected <R> R withRealm(String realmId, BiFunction<KeycloakSession, RealmModel, R> what) {
return inComittedTransaction(session -> {