aboutsummaryrefslogtreecommitdiff
path: root/stage1
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2016-11-25 16:48:28 -0500
committerChristopher Vogt <oss.nsp@cvogt.org>2017-02-01 23:10:48 -0500
commit00d9485f5597fdecc58461bd81df635fafbe494f (patch)
tree026f7f143d8cf5ae69e7afaa452d03180d3e04a8 /stage1
parent8939ebef01ae7a665781d99331e4d13e7b875a96 (diff)
downloadcbt-00d9485f5597fdecc58461bd81df635fafbe494f.tar.gz
cbt-00d9485f5597fdecc58461bd81df635fafbe494f.tar.bz2
cbt-00d9485f5597fdecc58461bd81df635fafbe494f.zip
Merge separate hashmaps for persistent cache into one
This isn’t type-safe, but re-using that same hashmap for both keys and classloaders allows to reduce the number of members in Context. Also we can re-use the same hashMap for other things as well in the coming commits, e.g. timestamps.
Diffstat (limited to 'stage1')
-rw-r--r--stage1/CachingClassLoader.scala2
-rw-r--r--stage1/ClassLoaderCache.scala18
-rw-r--r--stage1/ContextImplementation.scala5
-rw-r--r--stage1/KeyLockedLazyCache.scala51
-rw-r--r--stage1/Stage1.scala29
-rw-r--r--stage1/Stage1Lib.scala13
-rw-r--r--stage1/cbt.scala12
7 files changed, 57 insertions, 73 deletions
diff --git a/stage1/CachingClassLoader.scala b/stage1/CachingClassLoader.scala
index 4ddebda..38c0a1b 100644
--- a/stage1/CachingClassLoader.scala
+++ b/stage1/CachingClassLoader.scala
@@ -5,7 +5,7 @@ import scala.util.Try
trait CachingClassLoader extends ClassLoader{
def logger: Logger
- val cache = new KeyLockedLazyCache[String,Option[Class[_]]]( new ConcurrentHashMap, new ConcurrentHashMap, Some(logger) )
+ val cache = new KeyLockedLazyCache[Option[Class[_]]]( new ConcurrentHashMap[AnyRef,AnyRef], Some(logger) )
override def loadClass(name: String, resolve: Boolean) = {
cache.get( name, Try(super.loadClass(name, resolve)).toOption ).getOrElse(null)
}
diff --git a/stage1/ClassLoaderCache.scala b/stage1/ClassLoaderCache.scala
index e430ee1..2011562 100644
--- a/stage1/ClassLoaderCache.scala
+++ b/stage1/ClassLoaderCache.scala
@@ -2,22 +2,22 @@ package cbt
import java.net._
import java.util.concurrent.ConcurrentHashMap
-import collection.JavaConversions._
+import collection.JavaConverters._
case class ClassLoaderCache(
logger: Logger,
- private[cbt] permanentKeys: ConcurrentHashMap[String,AnyRef],
- private[cbt] permanentClassLoaders: ConcurrentHashMap[AnyRef,ClassLoader]
+ private[cbt] hashMap: ConcurrentHashMap[AnyRef,AnyRef]
){
- val persistent = new KeyLockedLazyCache(
- permanentKeys,
- permanentClassLoaders,
- Some(logger)
- )
+ val cache = new KeyLockedLazyCache[ClassLoader]( hashMap, Some(logger) )
override def toString = (
s"ClassLoaderCache("
++
- persistent.keys.keySet.toVector.map(_.toString.split(":").mkString("\n")).sorted.mkString("\n\n","\n\n","\n\n")
+ hashMap.asScala.collect{
+ case (key, value) if key.isInstanceOf[String] =>
+ key.toString.split(":").mkString("\n") -> value
+ }.toVector.sortBy(_._1).map{
+ case (key, value) => key + " -> " + hashMap.get(value)
+ }.mkString("\n\n","\n\n","\n\n")
++
")"
)
diff --git a/stage1/ContextImplementation.scala b/stage1/ContextImplementation.scala
index 152e606..6eb2e53 100644
--- a/stage1/ContextImplementation.scala
+++ b/stage1/ContextImplementation.scala
@@ -11,9 +11,8 @@ case class ContextImplementation(
startCompat: Long,
cbtHasChangedCompat: Boolean,
scalaVersionOrNull: String,
- permanentKeys: ConcurrentHashMap[String,AnyRef],
- permanentClassLoaders: ConcurrentHashMap[AnyRef,ClassLoader],
- taskCache: ConcurrentHashMap[AnyRef,AnyRef],
+ persistentCache: ConcurrentHashMap[AnyRef,AnyRef],
+ transientCache: ConcurrentHashMap[AnyRef,AnyRef],
cache: File,
cbtHome: File,
cbtRootHome: File,
diff --git a/stage1/KeyLockedLazyCache.scala b/stage1/KeyLockedLazyCache.scala
index 4eff5b2..2602523 100644
--- a/stage1/KeyLockedLazyCache.scala
+++ b/stage1/KeyLockedLazyCache.scala
@@ -4,59 +4,58 @@ import java.util.concurrent.ConcurrentHashMap
private[cbt] class LockableKey
/**
-A cache that lazily computes values if needed during lookup.
+A hashMap 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](
- val keys: ConcurrentHashMap[Key,AnyRef],
- val values: ConcurrentHashMap[AnyRef,Value],
+final private[cbt] class KeyLockedLazyCache[T <: AnyRef](
+ val hashMap: ConcurrentHashMap[AnyRef,AnyRef],
logger: Option[Logger]
){
- def get( key: Key, value: => Value ): Value = {
- val lockableKey = keys.synchronized{
- if( ! (keys containsKey key) ){
+ def get( key: AnyRef, value: => T ): T = {
+ val lockableKey = hashMap.synchronized{
+ if( ! (hashMap containsKey key) ){
val lockableKey = new LockableKey
//logger.foreach(_.resolver("CACHE MISS: " ++ key.toString))
- keys.put( key, lockableKey )
+ hashMap.put( key, lockableKey )
lockableKey
} else {
- val lockableKey = keys get key
+ val lockableKey = hashMap get key
//logger.foreach(_.resolver("CACHE HIT: " ++ lockableKey.toString ++ " -> " ++ key.toString))
lockableKey
}
}
import collection.JavaConversions._
- //logger.resolver("CACHE: \n" ++ keys.mkString("\n"))
+ //logger.resolver("CACHE: \n" ++ hashMap.mkString("\n"))
// synchronizing on key only, so asking for a particular key does
- // not block the whole cache, but just that cache entry
+ // not block the whole hashMap, but just that hashMap entry
lockableKey.synchronized{
- if( ! (values containsKey lockableKey) ){
- values.put( lockableKey, value )
+ if( ! (hashMap containsKey lockableKey) ){
+ hashMap.put( lockableKey, value )
}
- values get lockableKey
+ (hashMap get lockableKey).asInstanceOf[T]
}
}
- def update( key: Key, value: Value ): Value = {
- val lockableKey = keys get key
+ def update( key: AnyRef, value: T ): T = {
+ val lockableKey = hashMap get key
lockableKey.synchronized{
- values.put( lockableKey, value )
+ hashMap.put( lockableKey, value )
value
}
}
- def remove( key: Key ) = keys.synchronized{
- assert(keys containsKey key)
- val lockableKey = keys get key
+ def remove( key: AnyRef ) = hashMap.synchronized{
+ assert(hashMap containsKey key)
+ val lockableKey = hashMap get key
lockableKey.synchronized{
- if(values containsKey lockableKey){
- // this is so values in the process of being replaced (which mean they have a key but no value)
+ if(hashMap containsKey lockableKey){
+ // this is so hashMap in the process of being replaced (which mean they have a key but no value)
// are not being removed
- keys.remove( key )
- values.remove( lockableKey )
+ hashMap.remove( key )
+ hashMap.remove( lockableKey )
}
}
}
- def containsKey( key: Key ) = keys.synchronized{
- keys containsKey key
+ def containsKey( key: AnyRef ) = hashMap.synchronized{
+ hashMap containsKey key
}
}
diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala
index d559dd4..cd46d6b 100644
--- a/stage1/Stage1.scala
+++ b/stage1/Stage1.scala
@@ -45,11 +45,7 @@ case class Stage2Args(
cbtHome: File,
compatibilityTarget: File
){
- val ClassLoaderCache(
- logger,
- permanentKeys,
- permanentClassLoaders
- ) = classLoaderCache
+ val ClassLoaderCache( logger, persistentCache ) = classLoaderCache
}
object Stage1{
protected def newerThan( a: File, b: File ) ={
@@ -61,11 +57,7 @@ object Stage1{
val logger = new Logger( context.enabledLoggers, context.start )
val (changed, classLoader) = buildStage2(
buildStage1,
- ClassLoaderCache(
- logger,
- context.permanentKeys,
- context.permanentClassLoaders
- ),
+ ClassLoaderCache( logger, context.persistentCache ),
context.cbtHome,
context.cache
)
@@ -113,8 +105,8 @@ object Stage1{
)
logger.stage1(s"calling CbtDependency.classLoader")
- if( cbtHasChanged && classLoaderCache.persistent.containsKey( cbtDependency.classpath.string ) ) {
- classLoaderCache.persistent.remove( cbtDependency.classpath.string )
+ if( cbtHasChanged && classLoaderCache.cache.containsKey( cbtDependency.classpath.string ) ) {
+ classLoaderCache.cache.remove( cbtDependency.classpath.string )
} else {
assert(
buildStage1.compatibilityClasspath === cbtDependency.stage1Dependency.compatibilityDependency.classpath.string,
@@ -125,11 +117,11 @@ object Stage1{
"stage1 classpath different from NailgunLauncher"
)
assert(
- classLoaderCache.persistent.containsKey( cbtDependency.stage1Dependency.compatibilityDependency.classpath.string ),
+ classLoaderCache.cache.containsKey( cbtDependency.stage1Dependency.compatibilityDependency.classpath.string ),
"cbt unchanged, expected compatibility classloader to be cached"
)
assert(
- classLoaderCache.persistent.containsKey( cbtDependency.stage1Dependency.classpath.string ),
+ classLoaderCache.cache.containsKey( cbtDependency.stage1Dependency.classpath.string ),
"cbt unchanged, expected stage1/nailgun classloader to be cached"
)
}
@@ -167,18 +159,13 @@ object Stage1{
cbtHome: File,
buildStage1: BuildStage1Result,
start: java.lang.Long,
- classLoaderCacheKeys: ConcurrentHashMap[String,AnyRef],
- classLoaderCacheValues: ConcurrentHashMap[AnyRef,ClassLoader]
+ persistentCache: ConcurrentHashMap[AnyRef,AnyRef]
): Int = {
val args = Stage1ArgsParser(_args.toVector)
val logger = new Logger(args.enabledLoggers, start)
logger.stage1(s"Stage1 start")
- val classLoaderCache = ClassLoaderCache(
- logger,
- classLoaderCacheKeys,
- classLoaderCacheValues
- )
+ val classLoaderCache = ClassLoaderCache( logger, persistentCache )
val (cbtHasChanged, classLoader) = buildStage2( buildStage1, classLoaderCache, cbtHome, cache )
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala
index 273b9af..8fdde54 100644
--- a/stage1/Stage1Lib.scala
+++ b/stage1/Stage1Lib.scala
@@ -255,7 +255,7 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
)
val singleArgs = scalacOptions.map( "-S" ++ _ )
- val code =
+ val code =
redirectOutToErr{
System.err.println("Compiling to " ++ compileTarget.toString)
try{
@@ -285,6 +285,8 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
${files.sorted.mkString(" \\\n")}
"""
)
+
+ redirectOutToErr( e.printStackTrace )
ExitCode.Failure
}
}
@@ -416,6 +418,7 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
}
def classLoaderRecursion( dependency: Dependency, latest: Map[(String,String),Dependency], cache: ClassLoaderCache ): ClassLoader = {
+ // FIXME: shouldn't we be using KeyLockedLazyCache instead of hashmap directly here?
val d = dependency
val dependencies = dependency.dependencies
def dependencyClassLoader( latest: Map[(String,String),Dependency], cache: ClassLoaderCache ): ClassLoader = {
@@ -426,14 +429,14 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
classLoaderRecursion( dependencies.head, latest, cache )
} else{
val cp = d.dependencyClasspath.string
- if( dependencies.exists(_.needsUpdate) && cache.persistent.containsKey(cp) ){
- cache.persistent.remove(cp)
+ if( dependencies.exists(_.needsUpdate) && cache.cache.containsKey(cp) ){
+ cache.cache.remove(cp)
}
def cl = new MultiClassLoader( dependencies.map( classLoaderRecursion(_, latest, cache) ) )
if(d.isInstanceOf[BuildInterface])
cl // Don't cache builds right now. We need to fix invalidation first.
else
- cache.persistent.get( cp, cl )
+ cache.cache.get( cp, cl )
}
}
@@ -442,6 +445,6 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
if(d.isInstanceOf[BuildInterface])
cl
else
- cache.persistent.get( a.classpath.string, cl )
+ cache.cache.get( a.classpath.string, cl ).asInstanceOf[ClassLoader]
}
}
diff --git a/stage1/cbt.scala b/stage1/cbt.scala
index e324fa0..985f619 100644
--- a/stage1/cbt.scala
+++ b/stage1/cbt.scala
@@ -59,11 +59,8 @@ object `package`{
import subject._
val paths = CbtPaths(cbtHome, cache)
implicit def logger: Logger = new Logger(enabledLoggers, start)
- def classLoaderCache: ClassLoaderCache = new ClassLoaderCache(
- logger,
- permanentKeys,
- permanentClassLoaders
- )
+
+ def classLoaderCache: ClassLoaderCache = new ClassLoaderCache( logger, persistentCache )
def cbtDependency = {
import paths._
CbtDependency(cbtHasChanged, mavenCache, nailgunTarget, stage1Target, stage2Target, compatibilityTarget)
@@ -91,9 +88,8 @@ object `package`{
startCompat,
cbtHasChangedCompat,
scalaVersion.getOrElse(null),
- permanentKeys,
- permanentClassLoaders,
- taskCache,
+ persistentCache,
+ transientCache,
cache,
cbtHome,
cbtRootHome,