diff options
author | Christopher Vogt <oss.nsp@cvogt.org> | 2016-11-25 16:48:28 -0500 |
---|---|---|
committer | Christopher Vogt <oss.nsp@cvogt.org> | 2017-02-01 23:10:48 -0500 |
commit | 00d9485f5597fdecc58461bd81df635fafbe494f (patch) | |
tree | 026f7f143d8cf5ae69e7afaa452d03180d3e04a8 /stage1 | |
parent | 8939ebef01ae7a665781d99331e4d13e7b875a96 (diff) | |
download | cbt-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.scala | 2 | ||||
-rw-r--r-- | stage1/ClassLoaderCache.scala | 18 | ||||
-rw-r--r-- | stage1/ContextImplementation.scala | 5 | ||||
-rw-r--r-- | stage1/KeyLockedLazyCache.scala | 51 | ||||
-rw-r--r-- | stage1/Stage1.scala | 29 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 13 | ||||
-rw-r--r-- | stage1/cbt.scala | 12 |
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, |