Merge pull request #5301 from eatkins/classloader-close

Add closeClassLoader setting
This commit is contained in:
eugene yokota 2019-12-12 22:49:45 -05:00 committed by GitHub
commit b8f1edb6cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 33 additions and 13 deletions

View File

@ -32,9 +32,10 @@ final class BottomClassLoader extends ManagedClassLoader {
final URL[] dynamicClasspath,
final ReverseLookupClassLoader reverseLookupClassLoader,
final File tempDir,
final boolean close,
final boolean allowZombies,
final Logger logger) {
super(dynamicClasspath, reverseLookupClassLoader, allowZombies, logger);
super(dynamicClasspath, reverseLookupClassLoader, close, allowZombies, logger);
setTempDir(tempDir);
this.holder = holder;
this.parent = reverseLookupClassLoader;

View File

@ -20,9 +20,10 @@ final class FlatLoader extends ManagedClassLoader {
final URL[] urls,
final ClassLoader parent,
final File file,
final boolean close,
final boolean allowZombies,
final Logger logger) {
super(urls, parent, allowZombies, logger);
super(urls, parent, close, allowZombies, logger);
setTempDir(file);
}

View File

@ -12,9 +12,9 @@ import java.net.URL;
import sbt.util.Logger;
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) {
super(classpath, parent, allowZombies, logger);
super(classpath, parent, close, allowZombies, logger);
setTempDir(tempDir);
}

View File

@ -20,6 +20,7 @@ abstract class ManagedClassLoader extends URLClassLoader implements NativeLoader
private final AtomicBoolean closed = new AtomicBoolean(false);
private final AtomicBoolean printedWarning = new AtomicBoolean(false);
private final AtomicReference<ZombieClassLoader> zombieLoader = new AtomicReference<>();
private final boolean close;
private final boolean allowZombies;
private final Logger logger;
private final NativeLookup nativeLookup = new NativeLookup();
@ -29,8 +30,9 @@ abstract class ManagedClassLoader extends URLClassLoader implements NativeLoader
}
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);
this.close = close;
this.allowZombies = allowZombies;
this.logger = logger;
}
@ -103,8 +105,8 @@ abstract class ManagedClassLoader extends URLClassLoader implements NativeLoader
@Override
public void close() throws IOException {
final ZombieClassLoader zb = zombieLoader.getAndSet(null);
if (zb != null) zb.close();
if (closed.compareAndSet(false, true)) super.close();
if (zb != null && close) zb.close();
if (close && closed.compareAndSet(false, true)) super.close();
}
@Override

View File

@ -36,8 +36,12 @@ import sbt.util.Logger;
*/
final class ReverseLookupClassLoader extends ManagedClassLoader {
ReverseLookupClassLoader(
final URL[] urls, final ClassLoader parent, final boolean allowZombies, final Logger logger) {
super(urls, parent, allowZombies, logger);
final URL[] urls,
final ClassLoader parent,
final boolean close,
final boolean allowZombies,
final Logger logger) {
super(urls, parent, close, allowZombies, logger);
this.parent = parent;
}

View File

@ -205,7 +205,8 @@ object Defaults extends BuildCommon {
bgStop := bgStopTask.evaluated,
bgWaitFor := bgWaitForTask.evaluated,
bgCopyClasspath :== true,
allowZombieClassLoaders :== !SysProp.closeClassLoaders,
closeClassLoaders :== SysProp.closeClassLoaders,
allowZombieClassLoaders :== true,
)
private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =

View File

@ -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 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 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 useCoursier = settingKey[Boolean]("Use Coursier for dependency resolution.").withRank(BSetting)

View File

@ -44,6 +44,7 @@ private[sbt] object ClassLoaders {
else si.libraryJars.map(j => j -> IO.getModifiedTimeOrZero(j)).toSeq ++ rawCP
val exclude = dependencyJars(exportedProducts).value.toSet ++ si.libraryJars
val logger = state.value.globalLogging.full
val close = closeClassLoaders.value
val allowZombies = allowZombieClassLoaders.value
buildLayers(
strategy = classLoaderLayeringStrategy.value,
@ -55,6 +56,7 @@ private[sbt] object ClassLoaders {
tmp = IO.createUniqueDirectory(taskTemporaryDirectory.value),
scope = resolvedScoped.value.scope,
logger = logger,
close = close,
allowZombies = allowZombies,
)
}
@ -88,6 +90,7 @@ private[sbt] object ClassLoaders {
val allDeps = dependencyJars(dependencyClasspath).value.filterNot(exclude)
val logger = state.value.globalLogging.full
val allowZombies = allowZombieClassLoaders.value
val close = closeClassLoaders.value
val newLoader =
(classpath: Seq[File]) => {
val mappings = classpath.map(f => f.getName -> f).toMap
@ -102,6 +105,7 @@ private[sbt] object ClassLoaders {
tmp = taskTemporaryDirectory.value: @sbtUnchecked,
scope = resolvedScope,
logger = logger,
close = close,
allowZombies = allowZombies,
)
}
@ -136,11 +140,12 @@ private[sbt] object ClassLoaders {
tmp: File,
scope: Scope,
logger: Logger,
close: Boolean,
allowZombies: Boolean
): ClassLoader = {
val cpFiles = fullCP.map(_._1)
strategy match {
case Flat => new FlatLoader(cpFiles.urls, interfaceLoader, tmp, allowZombies, logger)
case Flat => new FlatLoader(cpFiles.urls, interfaceLoader, tmp, close, allowZombies, logger)
case _ =>
val layerDependencies = strategy match {
case _: AllLibraryJars => true
@ -206,6 +211,7 @@ private[sbt] object ClassLoaders {
new ReverseLookupClassLoaderHolder(
otherDependencies,
frameworkLayer,
close,
allowZombies,
logger
)
@ -225,7 +231,7 @@ private[sbt] object ClassLoaders {
cl.getParent match {
case dl: ReverseLookupClassLoaderHolder => dl.checkout(dynamicClasspath, tmp)
case _ =>
new LayeredClassLoader(dynamicClasspath.urls, cl, tmp, allowZombies, logger)
new LayeredClassLoader(dynamicClasspath.urls, cl, tmp, close, allowZombies, logger)
}
}
}

View File

@ -42,6 +42,7 @@ import scala.collection.JavaConverters._
private[internal] final class ReverseLookupClassLoaderHolder(
val classpath: Seq[File],
val parent: ClassLoader,
val closeThis: Boolean,
val allowZombies: Boolean,
val logger: Logger
) extends URLClassLoader(Array.empty, null) {
@ -62,7 +63,7 @@ private[internal] final class ReverseLookupClassLoaderHolder(
throw new IllegalStateException(msg)
}
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
}
reverseLookupClassLoader.setup(tempDir)
@ -71,6 +72,7 @@ private[internal] final class ReverseLookupClassLoaderHolder(
dynamicClasspath.map(_.toURI.toURL).toArray,
reverseLookupClassLoader,
tempDir,
closeThis,
allowZombies,
logger
)

View File

@ -5,3 +5,5 @@ version := "1.0"
scalaVersion := "2.12.10"
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.4.3"
Compile / closeClassLoaders := false