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 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;

View File

@ -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);
} }

View 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);
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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[_]] =

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 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)

View File

@ -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)
} }
} }
} }

View File

@ -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
) )

View File

@ -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