mirror of https://github.com/sbt/sbt.git
Merge pull request #5301 from eatkins/classloader-close
Add closeClassLoader setting
This commit is contained in:
commit
b8f1edb6cc
|
|
@ -32,9 +32,10 @@ final class BottomClassLoader extends ManagedClassLoader {
|
||||||
final URL[] dynamicClasspath,
|
final URL[] dynamicClasspath,
|
||||||
final ReverseLookupClassLoader reverseLookupClassLoader,
|
final ReverseLookupClassLoader reverseLookupClassLoader,
|
||||||
final File tempDir,
|
final File tempDir,
|
||||||
|
final boolean close,
|
||||||
final boolean allowZombies,
|
final boolean allowZombies,
|
||||||
final Logger logger) {
|
final Logger logger) {
|
||||||
super(dynamicClasspath, reverseLookupClassLoader, allowZombies, logger);
|
super(dynamicClasspath, reverseLookupClassLoader, close, allowZombies, logger);
|
||||||
setTempDir(tempDir);
|
setTempDir(tempDir);
|
||||||
this.holder = holder;
|
this.holder = holder;
|
||||||
this.parent = reverseLookupClassLoader;
|
this.parent = reverseLookupClassLoader;
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,10 @@ final class FlatLoader extends ManagedClassLoader {
|
||||||
final URL[] urls,
|
final URL[] urls,
|
||||||
final ClassLoader parent,
|
final ClassLoader parent,
|
||||||
final File file,
|
final File file,
|
||||||
|
final boolean close,
|
||||||
final boolean allowZombies,
|
final boolean allowZombies,
|
||||||
final Logger logger) {
|
final Logger logger) {
|
||||||
super(urls, parent, allowZombies, logger);
|
super(urls, parent, close, allowZombies, logger);
|
||||||
setTempDir(file);
|
setTempDir(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ import java.net.URL;
|
||||||
import sbt.util.Logger;
|
import sbt.util.Logger;
|
||||||
|
|
||||||
final class LayeredClassLoader extends ManagedClassLoader {
|
final class LayeredClassLoader extends ManagedClassLoader {
|
||||||
LayeredClassLoader(final URL[] classpath, final ClassLoader parent, final File tempDir, final
|
LayeredClassLoader(final URL[] classpath, final ClassLoader parent, final File tempDir, final boolean close, final
|
||||||
boolean allowZombies, final Logger logger) {
|
boolean allowZombies, final Logger logger) {
|
||||||
super(classpath, parent, allowZombies, logger);
|
super(classpath, parent, close, allowZombies, logger);
|
||||||
setTempDir(tempDir);
|
setTempDir(tempDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ abstract class ManagedClassLoader extends URLClassLoader implements NativeLoader
|
||||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
private final AtomicBoolean printedWarning = new AtomicBoolean(false);
|
private final AtomicBoolean printedWarning = new AtomicBoolean(false);
|
||||||
private final AtomicReference<ZombieClassLoader> zombieLoader = new AtomicReference<>();
|
private final AtomicReference<ZombieClassLoader> zombieLoader = new AtomicReference<>();
|
||||||
|
private final boolean close;
|
||||||
private final boolean allowZombies;
|
private final boolean allowZombies;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final NativeLookup nativeLookup = new NativeLookup();
|
private final NativeLookup nativeLookup = new NativeLookup();
|
||||||
|
|
@ -29,8 +30,9 @@ abstract class ManagedClassLoader extends URLClassLoader implements NativeLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedClassLoader(
|
ManagedClassLoader(
|
||||||
final URL[] urls, final ClassLoader parent, final boolean allowZombies, final Logger logger) {
|
final URL[] urls, final ClassLoader parent, final boolean close, final boolean allowZombies, final Logger logger) {
|
||||||
super(urls, parent);
|
super(urls, parent);
|
||||||
|
this.close = close;
|
||||||
this.allowZombies = allowZombies;
|
this.allowZombies = allowZombies;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
@ -103,8 +105,8 @@ abstract class ManagedClassLoader extends URLClassLoader implements NativeLoader
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
final ZombieClassLoader zb = zombieLoader.getAndSet(null);
|
final ZombieClassLoader zb = zombieLoader.getAndSet(null);
|
||||||
if (zb != null) zb.close();
|
if (zb != null && close) zb.close();
|
||||||
if (closed.compareAndSet(false, true)) super.close();
|
if (close && closed.compareAndSet(false, true)) super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,12 @@ import sbt.util.Logger;
|
||||||
*/
|
*/
|
||||||
final class ReverseLookupClassLoader extends ManagedClassLoader {
|
final class ReverseLookupClassLoader extends ManagedClassLoader {
|
||||||
ReverseLookupClassLoader(
|
ReverseLookupClassLoader(
|
||||||
final URL[] urls, final ClassLoader parent, final boolean allowZombies, final Logger logger) {
|
final URL[] urls,
|
||||||
super(urls, parent, allowZombies, logger);
|
final ClassLoader parent,
|
||||||
|
final boolean close,
|
||||||
|
final boolean allowZombies,
|
||||||
|
final Logger logger) {
|
||||||
|
super(urls, parent, close, allowZombies, logger);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,8 @@ object Defaults extends BuildCommon {
|
||||||
bgStop := bgStopTask.evaluated,
|
bgStop := bgStopTask.evaluated,
|
||||||
bgWaitFor := bgWaitForTask.evaluated,
|
bgWaitFor := bgWaitForTask.evaluated,
|
||||||
bgCopyClasspath :== true,
|
bgCopyClasspath :== true,
|
||||||
allowZombieClassLoaders :== !SysProp.closeClassLoaders,
|
closeClassLoaders :== SysProp.closeClassLoaders,
|
||||||
|
allowZombieClassLoaders :== true,
|
||||||
)
|
)
|
||||||
|
|
||||||
private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =
|
private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =
|
||||||
|
|
|
||||||
|
|
@ -327,6 +327,7 @@ object Keys {
|
||||||
val dependencyClasspathAsJars = taskKey[Classpath]("The classpath consisting of internal and external, managed and unmanaged dependencies, all as JARs.")
|
val dependencyClasspathAsJars = taskKey[Classpath]("The classpath consisting of internal and external, managed and unmanaged dependencies, all as JARs.")
|
||||||
val fullClasspathAsJars = taskKey[Classpath]("The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies, all as JARs.")
|
val fullClasspathAsJars = taskKey[Classpath]("The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies, all as JARs.")
|
||||||
val internalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on")
|
val internalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on")
|
||||||
|
val closeClassLoaders = settingKey[Boolean]("Close classloaders in run and test when the task completes.").withRank(DSetting)
|
||||||
val allowZombieClassLoaders = settingKey[Boolean]("Allow a classloader that has previously been closed by `run` or `test` to continue loading classes.")
|
val allowZombieClassLoaders = settingKey[Boolean]("Allow a classloader that has previously been closed by `run` or `test` to continue loading classes.")
|
||||||
|
|
||||||
val useCoursier = settingKey[Boolean]("Use Coursier for dependency resolution.").withRank(BSetting)
|
val useCoursier = settingKey[Boolean]("Use Coursier for dependency resolution.").withRank(BSetting)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ private[sbt] object ClassLoaders {
|
||||||
else si.libraryJars.map(j => j -> IO.getModifiedTimeOrZero(j)).toSeq ++ rawCP
|
else si.libraryJars.map(j => j -> IO.getModifiedTimeOrZero(j)).toSeq ++ rawCP
|
||||||
val exclude = dependencyJars(exportedProducts).value.toSet ++ si.libraryJars
|
val exclude = dependencyJars(exportedProducts).value.toSet ++ si.libraryJars
|
||||||
val logger = state.value.globalLogging.full
|
val logger = state.value.globalLogging.full
|
||||||
|
val close = closeClassLoaders.value
|
||||||
val allowZombies = allowZombieClassLoaders.value
|
val allowZombies = allowZombieClassLoaders.value
|
||||||
buildLayers(
|
buildLayers(
|
||||||
strategy = classLoaderLayeringStrategy.value,
|
strategy = classLoaderLayeringStrategy.value,
|
||||||
|
|
@ -55,6 +56,7 @@ private[sbt] object ClassLoaders {
|
||||||
tmp = IO.createUniqueDirectory(taskTemporaryDirectory.value),
|
tmp = IO.createUniqueDirectory(taskTemporaryDirectory.value),
|
||||||
scope = resolvedScoped.value.scope,
|
scope = resolvedScoped.value.scope,
|
||||||
logger = logger,
|
logger = logger,
|
||||||
|
close = close,
|
||||||
allowZombies = allowZombies,
|
allowZombies = allowZombies,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +90,7 @@ private[sbt] object ClassLoaders {
|
||||||
val allDeps = dependencyJars(dependencyClasspath).value.filterNot(exclude)
|
val allDeps = dependencyJars(dependencyClasspath).value.filterNot(exclude)
|
||||||
val logger = state.value.globalLogging.full
|
val logger = state.value.globalLogging.full
|
||||||
val allowZombies = allowZombieClassLoaders.value
|
val allowZombies = allowZombieClassLoaders.value
|
||||||
|
val close = closeClassLoaders.value
|
||||||
val newLoader =
|
val newLoader =
|
||||||
(classpath: Seq[File]) => {
|
(classpath: Seq[File]) => {
|
||||||
val mappings = classpath.map(f => f.getName -> f).toMap
|
val mappings = classpath.map(f => f.getName -> f).toMap
|
||||||
|
|
@ -102,6 +105,7 @@ private[sbt] object ClassLoaders {
|
||||||
tmp = taskTemporaryDirectory.value: @sbtUnchecked,
|
tmp = taskTemporaryDirectory.value: @sbtUnchecked,
|
||||||
scope = resolvedScope,
|
scope = resolvedScope,
|
||||||
logger = logger,
|
logger = logger,
|
||||||
|
close = close,
|
||||||
allowZombies = allowZombies,
|
allowZombies = allowZombies,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -136,11 +140,12 @@ private[sbt] object ClassLoaders {
|
||||||
tmp: File,
|
tmp: File,
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
|
close: Boolean,
|
||||||
allowZombies: Boolean
|
allowZombies: Boolean
|
||||||
): ClassLoader = {
|
): ClassLoader = {
|
||||||
val cpFiles = fullCP.map(_._1)
|
val cpFiles = fullCP.map(_._1)
|
||||||
strategy match {
|
strategy match {
|
||||||
case Flat => new FlatLoader(cpFiles.urls, interfaceLoader, tmp, allowZombies, logger)
|
case Flat => new FlatLoader(cpFiles.urls, interfaceLoader, tmp, close, allowZombies, logger)
|
||||||
case _ =>
|
case _ =>
|
||||||
val layerDependencies = strategy match {
|
val layerDependencies = strategy match {
|
||||||
case _: AllLibraryJars => true
|
case _: AllLibraryJars => true
|
||||||
|
|
@ -206,6 +211,7 @@ private[sbt] object ClassLoaders {
|
||||||
new ReverseLookupClassLoaderHolder(
|
new ReverseLookupClassLoaderHolder(
|
||||||
otherDependencies,
|
otherDependencies,
|
||||||
frameworkLayer,
|
frameworkLayer,
|
||||||
|
close,
|
||||||
allowZombies,
|
allowZombies,
|
||||||
logger
|
logger
|
||||||
)
|
)
|
||||||
|
|
@ -225,7 +231,7 @@ private[sbt] object ClassLoaders {
|
||||||
cl.getParent match {
|
cl.getParent match {
|
||||||
case dl: ReverseLookupClassLoaderHolder => dl.checkout(dynamicClasspath, tmp)
|
case dl: ReverseLookupClassLoaderHolder => dl.checkout(dynamicClasspath, tmp)
|
||||||
case _ =>
|
case _ =>
|
||||||
new LayeredClassLoader(dynamicClasspath.urls, cl, tmp, allowZombies, logger)
|
new LayeredClassLoader(dynamicClasspath.urls, cl, tmp, close, allowZombies, logger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import scala.collection.JavaConverters._
|
||||||
private[internal] final class ReverseLookupClassLoaderHolder(
|
private[internal] final class ReverseLookupClassLoaderHolder(
|
||||||
val classpath: Seq[File],
|
val classpath: Seq[File],
|
||||||
val parent: ClassLoader,
|
val parent: ClassLoader,
|
||||||
|
val closeThis: Boolean,
|
||||||
val allowZombies: Boolean,
|
val allowZombies: Boolean,
|
||||||
val logger: Logger
|
val logger: Logger
|
||||||
) extends URLClassLoader(Array.empty, null) {
|
) extends URLClassLoader(Array.empty, null) {
|
||||||
|
|
@ -62,7 +63,7 @@ private[internal] final class ReverseLookupClassLoaderHolder(
|
||||||
throw new IllegalStateException(msg)
|
throw new IllegalStateException(msg)
|
||||||
}
|
}
|
||||||
val reverseLookupClassLoader = cached.getAndSet(null) match {
|
val reverseLookupClassLoader = cached.getAndSet(null) match {
|
||||||
case null => new ReverseLookupClassLoader(urls, parent, allowZombies, logger)
|
case null => new ReverseLookupClassLoader(urls, parent, closeThis, allowZombies, logger)
|
||||||
case c => c
|
case c => c
|
||||||
}
|
}
|
||||||
reverseLookupClassLoader.setup(tempDir)
|
reverseLookupClassLoader.setup(tempDir)
|
||||||
|
|
@ -71,6 +72,7 @@ private[internal] final class ReverseLookupClassLoaderHolder(
|
||||||
dynamicClasspath.map(_.toURI.toURL).toArray,
|
dynamicClasspath.map(_.toURI.toURL).toArray,
|
||||||
reverseLookupClassLoader,
|
reverseLookupClassLoader,
|
||||||
tempDir,
|
tempDir,
|
||||||
|
closeThis,
|
||||||
allowZombies,
|
allowZombies,
|
||||||
logger
|
logger
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,5 @@ version := "1.0"
|
||||||
scalaVersion := "2.12.10"
|
scalaVersion := "2.12.10"
|
||||||
|
|
||||||
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.4.3"
|
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.4.3"
|
||||||
|
|
||||||
|
Compile / closeClassLoaders := false
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue