Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ThreadLocal with a hashtable to support reliable cleanup #588

Merged
merged 2 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.jboss.arquillian.core.api.threading.ExecutorService;
import org.jboss.arquillian.core.impl.context.ApplicationContextImpl;
import org.jboss.arquillian.core.impl.threading.ThreadedExecutorService;
import org.jboss.arquillian.core.spi.ArquillianThreadLocal;
import org.jboss.arquillian.core.spi.EventContext;
import org.jboss.arquillian.core.spi.EventPoint;
import org.jboss.arquillian.core.spi.Extension;
Expand Down Expand Up @@ -66,8 +67,8 @@ public class ManagerImpl implements Manager {
* the higher level event will get the exception and re-fire it on the bus. We need to keep track of which exceptions
* has been handled in the call chain so we can re-throw without re-firing on a higher level.
*/
private ThreadLocal<Set<Class<? extends Throwable>>> handledThrowables =
new ThreadLocal<Set<Class<? extends Throwable>>>() {
private ArquillianThreadLocal<Set<Class<? extends Throwable>>> handledThrowables =
new ArquillianThreadLocal<Set<Class<? extends Throwable>>>() {
@Override
protected Set<Class<? extends Throwable>> initialValue() {
return new HashSet<Class<? extends Throwable>>();
Expand Down Expand Up @@ -279,6 +280,8 @@ public void shutdown() {
runtimeLogger.clear();

handledThrowables.remove();
//Force cleanup:
handledThrowables.clear();
}
if (shutdownException != null) {
UncheckedThrow.throwUnchecked(shutdownException);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.jboss.arquillian.core.spi;

import java.util.Hashtable;

/**
* Mapping for ThreadId to a value. Same as "ThreadLocal", but with simpler cleanup.
*
*/
public class ArquillianThreadLocal<T> {
private Hashtable<Long, T> table = new Hashtable<Long, T>();

protected T initialValue() {
return null;
}

/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
long threadId = t.getId();

if (table.containsKey(threadId)) {
return table.get(threadId);
}
else {
T value = initialValue();
table.put(threadId, value);
return value;
}
}

/**
* Removes the current thread's value for this thread-local
* variable.
*
*/
public void remove() {
Thread t = Thread.currentThread();
long threadId = t.getId();

if (table.containsKey(threadId)) {
table.remove(threadId);
}
}

/**
* Clears the cache
*/
public void clear() {
table.clear();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import org.jboss.arquillian.core.spi.ArquillianThreadLocal;
import org.jboss.arquillian.core.spi.Validate;

/**
Expand All @@ -33,7 +35,7 @@ public abstract class AbstractContext<T> implements Context, IdBoundContext<T> {

private ConcurrentHashMap<T, ObjectStore> stores;

private ThreadLocal<Stack<StoreHolder<T>>> activeStore = new ThreadLocal<Stack<StoreHolder<T>>>() {
private ArquillianThreadLocal<Stack<StoreHolder<T>>> activeStore = new ArquillianThreadLocal<Stack<StoreHolder<T>>>() {

@Override
protected Stack<StoreHolder<T>> initialValue() {
Expand Down Expand Up @@ -105,6 +107,8 @@ public void clearAll() {
deactivateAll();
}
activeStore.remove();
//Force cleanup:
activeStore.clear();
for (Map.Entry<T, ObjectStore> entry : stores.entrySet()) {
entry.getValue().clear();
}
Expand Down