Skip to content
Merged
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
@@ -1,9 +1,12 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.gradle.internal.isolation;

import com.google.common.collect.Sets;
import de.monticore.gradle.internal.io.PrefixStream;
import de.monticore.gradle.internal.io.PrintStreamThreadProxy;
import org.gradle.api.file.FileCollection;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;

import javax.annotation.Nullable;
import java.io.Closeable;
Expand All @@ -27,12 +30,18 @@
public class CachedIsolation<T> {

protected final List<IIsolationData<T>> internalRunners = Collections.synchronizedList(new LinkedList<>());
protected final Logger logger = Logging.getLogger(CachedIsolation.class);

/**
* Time (in ms) in which the close threshold timer is checked
*/
protected final long closeThresholdTimer = 2 * 1000; // 6 seconds by default

/**
* Time (in ms) after the last use of an isolated classloader before its
* allocated resources are freed
*/
protected final long closeThreshold = 6 * 1000; // 6 seconds
protected long closeThreshold = 6 * 1000; // 6 seconds by default

/**
* We periodically clean up the open classloaders
Expand All @@ -56,11 +65,21 @@ public class CachedIsolation<T> {
*/
protected int staggerCount;

/**
* The threshold to use to check for unused classloaders
* @param closeThreshold the new threshold
*/
public void setCloseThreshold(long closeThreshold) {
logger.debug("Setting close threshold to {} ", closeThreshold );
this.closeThreshold = closeThreshold;
}

/**
*
* @param staggeredStartUpFixedDelay the (fixed) time between the first and all further runners
* @param staggeredStartUpDelayPerRunner the time between the startup of individual runners
*/
@Deprecated
public void setStaggeredStartupParams(int staggeredStartUpFixedDelay, int staggeredStartUpDelayPerRunner) {
this.staggeredStartUpFixedDelay = staggeredStartUpFixedDelay;
this.staggeredStartUpDelayPerRunner = staggeredStartUpDelayPerRunner;
Expand All @@ -72,9 +91,17 @@ protected synchronized void setupTimer() {
cleanupTimer.schedule(new TimerTask() {
@Override
public void run() {
CachedIsolation.this.cleanupOld();
CachedIsolation.this.cleanupOld(closeThreshold);
}
}, closeThreshold, closeThreshold);
}, closeThresholdTimer, closeThresholdTimer);
}

/**
* Mark all internal runers as ready to be unloaded
*/
public void markForErasure() {
logger.debug("Marking forErasure");
this.internalRunners.forEach(r -> ((IsolationData<?>)r).lastRun = 0);
}

/**
Expand All @@ -88,14 +115,16 @@ protected synchronized IIsolationData<T> getLoader(Predicate<T> predicate, Suppl
.filter(x -> predicate.test(x.getExtraData()))
.findAny();
if (d.isPresent()) {
logger.debug("Reusing existing runner " + d.get().getUUID());
d.get().setRunning(true);
return d.get();
}
this.cleanupOld();
this.cleanupOld(closeThreshold);
final long staggerWait = getWaitForStaggeredStartup();
this.lastStartup = System.currentTimeMillis();
if (staggerWait <= 0) {
IsolationData<T> data = new IsolationData<>();
logger.debug("Creating new loader " + data.getUUID());
data.classLoader = getClassLoader((URLClassLoader) Thread.currentThread().getContextClassLoader(), supplier);
data.running = true;
data.extraData = supplier.get();
Expand Down Expand Up @@ -142,7 +171,7 @@ protected int getWaitForStaggeredStartup() {
* (and thus are not isolated)
*/
protected Set<String> getPassThroughPackages() {
return Set.of("org.gradle");
return Sets.newHashSet("org.gradle");
}

protected ClassLoader getClassLoader(URLClassLoader contextClassLoader, Supplier<T> supplier) {
Expand Down Expand Up @@ -297,16 +326,26 @@ protected void redirectStream(PrintStreamThreadProxy ps, String prefix) {
ps.setRedirect(new PrefixStream(ps.getOriginal(), prefix));
}

/**
* Cleanup all (unused) class loaders
*/
public void cleanupAll() {
this.cleanupOld(0);
}

/**
* Close unused classloaders to free up memory
* @param pCloseThreshold the threshold to use
*/
protected synchronized void cleanupOld() {
long threshold = System.currentTimeMillis() - this.closeThreshold;
protected synchronized void cleanupOld(long pCloseThreshold) {
long threshold = System.currentTimeMillis() - pCloseThreshold;
Iterator<IIsolationData<T>> isolated = this.internalRunners.iterator();
logger.debug("Running cleanup thread");
while (isolated.hasNext()) {
IIsolationData<T> data = isolated.next();
logger.debug(" - {} - {} - {}", data.isRunning() ? "R" : "I", data.getLastRun(), data.getUUID());
if (!data.isRunning() && data.getLastRun() < threshold){
logger.debug(" - close ");
if (data.getClassLoader() instanceof Closeable) {
// Close closeable classloaders
try {
Expand All @@ -332,6 +371,8 @@ protected static class IsolationData<T> implements IIsolationData<T> {

protected T extraData;

protected final UUID uuid = UUID.randomUUID();

@Override
public ClassLoader getClassLoader() {
return classLoader;
Expand Down Expand Up @@ -368,8 +409,14 @@ public void close() {
this.running = false;
this.lastRun = System.currentTimeMillis();
}

@Override
public UUID getUUID() {
return this.uuid;
}
}

@Deprecated
protected static class StaggeredIsolationData<T> implements IIsolationData<T> {
protected Optional<IIsolationData<T>> actual = Optional.empty();
protected final Supplier<IIsolationData<T>> supplier;
Expand Down Expand Up @@ -419,6 +466,11 @@ public long getLastRun() {
public void close() {
getActual().close();
}

@Override
public UUID getUUID() {
return getActual().getUUID();
}
}

protected interface IIsolationData<T> extends AutoCloseable {
Expand All @@ -436,6 +488,8 @@ protected interface IIsolationData<T> extends AutoCloseable {

@Override
void close();

UUID getUUID();
}

/**
Expand Down
Loading