diff options
Diffstat (limited to 'stage1')
-rw-r--r-- | stage1/ClassLoaderCache.scala | 69 | ||||
-rw-r--r-- | stage1/ClassPath.scala | 2 | ||||
-rw-r--r-- | stage1/KeyLockedLazyCache.scala | 33 | ||||
-rw-r--r-- | stage1/Stage1.scala | 7 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 5 | ||||
-rw-r--r-- | stage1/resolver.scala | 7 |
6 files changed, 66 insertions, 57 deletions
diff --git a/stage1/ClassLoaderCache.scala b/stage1/ClassLoaderCache.scala index 18a0d0e..35008f0 100644 --- a/stage1/ClassLoaderCache.scala +++ b/stage1/ClassLoaderCache.scala @@ -1,25 +1,60 @@ package cbt import java.net._ +import java.util.concurrent.ConcurrentHashMap -private[cbt] object ClassLoaderCache{ - private val cache = NailgunLauncher.classLoaderCache - def get( classpath: ClassPath )(implicit logger: Logger): ClassLoader - = cache.synchronized{ - val lib = new Stage1Lib(logger) - val key = classpath.strings.sorted.mkString(":") - if( cache.containsKey(key) ){ - logger.resolver("CACHE HIT: "++key) - cache.get(key) - } else { - logger.resolver("CACHE MISS: "++key) - val cl = new cbt.URLClassLoader( classpath, ClassLoader.getSystemClassLoader ) - cache.put( key, cl ) - cl +class ClassLoaderCache(logger: Logger){ + val permanent = new KeyLockedLazyCache( + NailgunLauncher.classLoaderCache.asInstanceOf[ConcurrentHashMap[String,AnyRef]], + NailgunLauncher.classLoaderCache.asInstanceOf[ConcurrentHashMap[AnyRef,ClassLoader]], + logger + ) + val transient = new KeyLockedLazyCache( + new ConcurrentHashMap[String,AnyRef], + new ConcurrentHashMap[AnyRef,ClassLoader], + logger + ) +} + +private[cbt] class LockableKey +/** +A cache that lazily computes values if needed during lookup. +Locking occurs on the key, so separate keys can be looked up +simultaneously without a deadlock. +*/ +final private[cbt] class KeyLockedLazyCache[Key <: AnyRef,Value <: AnyRef]( + keys: ConcurrentHashMap[Key,AnyRef], + builds: ConcurrentHashMap[AnyRef,Value], + logger: Logger +){ + def get( key: Key, value: => Value ): Value = { + val keyObject = keys.synchronized{ + if( ! (keys containsKey key) ){ + logger.resolver("CACHE MISS: " ++ key.toString) + keys.put( key, new LockableKey ) + } else { + logger.resolver("CACHE HIT: " ++ key.toString) + } + keys get key + } + import collection.JavaConversions._ + logger.resolver("CACHE: \n" ++ keys.mkString("\n")) + def k = ClassPath(new java.io.File("c")).asInstanceOf[Key] + // synchronizing on key only, so asking for a particular key does + // not block the whole cache, but just that cache entry + key.synchronized{ + if( ! (builds containsKey keyObject) ){ + builds.put( keyObject, value ) + } + builds get keyObject } } - def remove( classpath: ClassPath ) = { - val key = classpath.strings.sorted.mkString(":") - cache.remove( key ) + def remove( key: Key ) = keys.synchronized{ + if( (keys containsKey key) ){ + keys.put( key, new LockableKey ) + } + val keyObject = keys get key + keys.remove( key ) + builds.remove( keyObject ) } } diff --git a/stage1/ClassPath.scala b/stage1/ClassPath.scala index 66a1b44..96963e4 100644 --- a/stage1/ClassPath.scala +++ b/stage1/ClassPath.scala @@ -25,6 +25,6 @@ case class ClassPath(files: Seq[File]){ def string = strings.mkString( File.pathSeparator ) def strings = files.map{ f => f.string ++ ( if(f.isDirectory) "/" else "" ) - } + }.sorted def toConsole = string } diff --git a/stage1/KeyLockedLazyCache.scala b/stage1/KeyLockedLazyCache.scala deleted file mode 100644 index c8b37ea..0000000 --- a/stage1/KeyLockedLazyCache.scala +++ /dev/null @@ -1,33 +0,0 @@ -/* -package cbt -import java.util.concurrent.ConcurrentHashMap -import scala.concurrent.Future - -/** -A cache that lazily computes values if needed during lookup. -Locking occurs on the key, so separate keys can be looked up -simultaneously without a deadlock. -*/ -final private[cbt] class KeyLockedLazyCache[Key <: AnyRef,Value]{ - private val keys = new ConcurrentHashMap[Key,LockableKey]() - private val builds = new ConcurrentHashMap[LockableKey,Value]() - - private class LockableKey - def get( key: Key, value: => Value ): Value = { - val keyObject = keys.synchronized{ - if( ! (keys containsKey key) ){ - keys.put( key, new LockableKey ) - } - keys get key - } - // synchronizing on key only, so asking for a particular key does - // not block the whole cache, but just that cache entry - key.synchronized{ - if( ! (builds containsKey keyObject) ){ - builds.put( keyObject, value ) - } - builds get keyObject - } - } -} -*/ diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index a593c03..b1017f7 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -50,18 +50,21 @@ object Stage1{ val src = stage2.listFiles.toVector.filter(_.isFile).filter(_.toString.endsWith(".scala")) val changeIndicator = stage2Target ++ "/cbt/Build.class" + + val classLoaderCache = new ClassLoaderCache(logger) logger.stage1("before conditionally running zinc to recompile CBT") if( src.exists(newerThan(_, changeIndicator)) ) { val stage1Classpath = CbtDependency()(logger).dependencyClasspath logger.stage1("cbt.lib has changed. Recompiling with cp: " ++ stage1Classpath.string) - zinc( true, src, stage2Target, stage1Classpath, Seq("-deprecation") )( zincVersion = "0.3.9", scalaVersion = constants.scalaVersion ) + zinc( true, src, stage2Target, stage1Classpath, classLoaderCache, Seq("-deprecation") )( zincVersion = "0.3.9", scalaVersion = constants.scalaVersion ) } logger.stage1(s"[$now] calling CbtDependency.classLoader") + logger.stage1(s"[$now] Run Stage2") val ExitCode(exitCode) = /*trapExitCode*/{ // this - runMain( mainClass, cwd +: args.drop(1).toVector, CbtDependency()(logger).classLoader ) + runMain( mainClass, cwd +: args.drop(1).toVector, CbtDependency()(logger).classLoader(classLoaderCache) ) } logger.stage1(s"[$now] Stage1 end") System.exit(exitCode) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index d24ba52..6a8a0ba 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -30,7 +30,7 @@ object TrappedExitCode{ } } -case class Context( cwd: File, args: Seq[String], logger: Logger ) +case class Context( cwd: File, args: Seq[String], logger: Logger, classLoaderCache: ClassLoaderCache ) class BaseLib{ def realpath(name: File) = new File(Paths.get(name.getAbsolutePath).normalize.toString) @@ -130,6 +130,7 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ files: Seq[File], compileTarget: File, classpath: ClassPath, + classLoaderCache: ClassLoaderCache, extraArgs: Seq[String] = Seq() )( zincVersion: String, scalaVersion: String ): Unit = { @@ -176,7 +177,7 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ "-cp", cp, "-d", compileTarget.toString ) ++ extraArgs.map("-S"++_) ++ files.map(_.toString), - zinc.classLoader + zinc.classLoader(classLoaderCache) ) } diff --git a/stage1/resolver.scala b/stage1/resolver.scala index 98955cb..8dde321 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -87,7 +87,7 @@ abstract class Dependency{ } private object classLoaderCache extends Cache[URLClassLoader] - def classLoader: URLClassLoader = classLoaderCache{ + def classLoader( classLoaderCache: ClassLoaderCache ): URLClassLoader = { if( concurrencyEnabled ){ // trigger concurrent building / downloading dependencies exportClasspathConcurrently @@ -112,7 +112,10 @@ abstract class Dependency{ if(cacheDependencyClassLoader){ new URLClassLoader( buildClassPath, - ClassLoaderCache.get( cachedClassPath ) + classLoaderCache.permanent.get( + cachedClassPath.string, + cbt.URLClassLoader( classpath, ClassLoader.getSystemClassLoader ) + ) ) } else { new URLClassLoader( |