aboutsummaryrefslogtreecommitdiff
path: root/stage1
diff options
context:
space:
mode:
Diffstat (limited to 'stage1')
-rw-r--r--stage1/ClassLoaderCache.scala69
-rw-r--r--stage1/ClassPath.scala2
-rw-r--r--stage1/KeyLockedLazyCache.scala33
-rw-r--r--stage1/Stage1.scala7
-rw-r--r--stage1/Stage1Lib.scala5
-rw-r--r--stage1/resolver.scala7
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(