diff options
-rw-r--r-- | compatibility/Context.java | 5 | ||||
-rw-r--r-- | nailgun_launcher/CbtURLClassLoader.java | 5 | ||||
-rw-r--r-- | nailgun_launcher/ClassLoaderCache2.java | 37 | ||||
-rw-r--r-- | nailgun_launcher/EarlyDependencies.java | 2 | ||||
-rw-r--r-- | nailgun_launcher/JavaCache.java | 41 | ||||
-rw-r--r-- | nailgun_launcher/NailgunLauncher.java | 16 | ||||
-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 | ||||
-rw-r--r-- | stage2/BasicBuild.scala | 2 | ||||
-rw-r--r-- | stage2/Stage2.scala | 3 | ||||
-rw-r--r-- | stage2/ToolsTasks.scala | 2 | ||||
-rw-r--r-- | test/test.scala | 3 |
17 files changed, 113 insertions, 133 deletions
diff --git a/compatibility/Context.java b/compatibility/Context.java index 1ec0f54..5a0f9c6 100644 --- a/compatibility/Context.java +++ b/compatibility/Context.java @@ -11,9 +11,8 @@ public abstract class Context{ public abstract Long startCompat(); public abstract Boolean cbtHasChangedCompat(); public abstract String scalaVersionOrNull(); // needed to propagate scalaVersion to dependendee builds - public abstract ConcurrentHashMap<String,Object> permanentKeys(); - public abstract ConcurrentHashMap<Object,ClassLoader> permanentClassLoaders(); - public abstract ConcurrentHashMap<Object,Object> taskCache(); + public abstract ConcurrentHashMap<Object,Object> persistentCache(); + public abstract ConcurrentHashMap<Object,Object> transientCache(); public abstract File cache(); public abstract File cbtHome(); public abstract File cbtRootHome(); // REMOVE diff --git a/nailgun_launcher/CbtURLClassLoader.java b/nailgun_launcher/CbtURLClassLoader.java index 38fc905..e3d597e 100644 --- a/nailgun_launcher/CbtURLClassLoader.java +++ b/nailgun_launcher/CbtURLClassLoader.java @@ -15,10 +15,7 @@ public class CbtURLClassLoader extends java.net.URLClassLoader{ + "\n)" ); } - ClassLoaderCache2<Class> cache = new ClassLoaderCache2<Class>( - new ConcurrentHashMap<String, Object>(), - new ConcurrentHashMap<Object, Class>() - ); + JavaCache<Class> cache = new JavaCache<Class>( new ConcurrentHashMap<Object,Object>() ); public Class loadClass(String name) throws ClassNotFoundException{ Class _class = super.loadClass(name); if(_class == null) throw new ClassNotFoundException(name); diff --git a/nailgun_launcher/ClassLoaderCache2.java b/nailgun_launcher/ClassLoaderCache2.java deleted file mode 100644 index bf9ca3b..0000000 --- a/nailgun_launcher/ClassLoaderCache2.java +++ /dev/null @@ -1,37 +0,0 @@ -package cbt; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import static java.io.File.pathSeparator; -import static cbt.Stage0Lib.*; - -final class ClassLoaderCache2<T>{ - ConcurrentHashMap<String,Object> keys; - ConcurrentHashMap<Object,T> values; - - public ClassLoaderCache2( - ConcurrentHashMap<String,Object> keys, - ConcurrentHashMap<Object,T> values - ){ - this.keys = keys; - this.values = values; - } - - public T get( String key ){ - return values.get( - keys.get( key ) - ); - } - - public Boolean contains( String key ){ - return keys.containsKey( key ); - } - - public T put( T value, String key ){ - LockableKey2 keyObject = new LockableKey2(); - keys.put( key, keyObject ); - values.put( keyObject, value ); - return value; - } -} -class LockableKey2{}
\ No newline at end of file diff --git a/nailgun_launcher/EarlyDependencies.java b/nailgun_launcher/EarlyDependencies.java index 8f1962b..fdb54b5 100644 --- a/nailgun_launcher/EarlyDependencies.java +++ b/nailgun_launcher/EarlyDependencies.java @@ -28,7 +28,7 @@ class EarlyDependencies{ String scalaLibrary_2_10_6_File; public EarlyDependencies( - String mavenCache, String mavenUrl, ClassLoaderCache2<ClassLoader> classLoaderCache, ClassLoader rootClassLoader + String mavenCache, String mavenUrl, JavaCache<ClassLoader> classLoaderCache, ClassLoader rootClassLoader ) throws Throwable { scalaReflect_2_11_8_File = mavenCache + "/org/scala-lang/scala-reflect/2.11.8/scala-reflect-2.11.8.jar"; scalaCompiler_2_11_8_File = mavenCache + "/org/scala-lang/scala-compiler/2.11.8/scala-compiler-2.11.8.jar"; diff --git a/nailgun_launcher/JavaCache.java b/nailgun_launcher/JavaCache.java new file mode 100644 index 0000000..56730df --- /dev/null +++ b/nailgun_launcher/JavaCache.java @@ -0,0 +1,41 @@ +package cbt; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import static java.io.File.pathSeparator; +import static cbt.Stage0Lib.*; + +final class JavaCache<T>{ + ConcurrentHashMap<Object,Object> hashMap; + + public JavaCache( + ConcurrentHashMap<Object,Object> hashMap + ){ + this.hashMap = hashMap; + } + + public T get( Object key ){ + @SuppressWarnings("unchecked") + T t = (T) hashMap.get( + hashMap.get( key ) + ); + return t; + } + + public Boolean contains( Object key/*, Long timestamp*/ ){ + return hashMap.containsKey( key );/* && ( + (Long) hashMap.get( hashMap.get( hashMap.get(key) ) ) >= timestamp + );*/ + } + + public T put( Object value, Object key/*, Long timestamp*/ ){ + LockableJavaKey keyObject = new LockableJavaKey(); + hashMap.put( key, keyObject ); + hashMap.put( keyObject, value ); + //hashMap.put( value, timestamp ); + @SuppressWarnings("unchecked") + T t = (T) value; + return t; + } +} +class LockableJavaKey{} diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java index 944daf8..0b41888 100644 --- a/nailgun_launcher/NailgunLauncher.java +++ b/nailgun_launcher/NailgunLauncher.java @@ -15,9 +15,8 @@ import static java.io.File.pathSeparator; */ public class NailgunLauncher{ /** Persistent cache for caching classloaders for the JVM life time. */ - private final static ClassLoaderCache2<ClassLoader> classLoaderCache = new ClassLoaderCache2<ClassLoader>( - new ConcurrentHashMap<String,Object>(), - new ConcurrentHashMap<Object,ClassLoader>() + private final static JavaCache<ClassLoader> classLoaderCache = new JavaCache<ClassLoader>( + new ConcurrentHashMap<Object,Object>() ); public final static SecurityManager initialSecurityManager @@ -35,9 +34,8 @@ public class NailgunLauncher{ ((File) get(context, "cache")).toString() + "/", ((File) get(context, "cbtHome")).toString(), ((File) get(context, "compatibilityTarget")).toString() + "/", - new ClassLoaderCache2<ClassLoader>( - (ConcurrentHashMap<String,Object>) get(context, "permanentKeys"), - (ConcurrentHashMap<Object,ClassLoader>) get(context, "permanentClassLoaders") + new JavaCache<ClassLoader>( + (ConcurrentHashMap) get(context, "persistentCache") ) ); return @@ -93,12 +91,12 @@ public class NailgunLauncher{ .getMethod( "run", String[].class, File.class, File.class, BuildStage1Result.class, - Long.class, ConcurrentHashMap.class, ConcurrentHashMap.class + Long.class, ConcurrentHashMap.class ) .invoke( null, (Object) args, new File(cache), new File(CBT_HOME), res, - start, classLoaderCache.keys, classLoaderCache.values + start, classLoaderCache.hashMap ) ); } catch (java.lang.reflect.InvocationTargetException e) { @@ -115,7 +113,7 @@ public class NailgunLauncher{ } public static BuildStage1Result buildStage1( - Boolean changed, long start, String cache, String cbtHome, String compatibilityTarget, ClassLoaderCache2<ClassLoader> classLoaderCache + Boolean changed, long start, String cache, String cbtHome, String compatibilityTarget, JavaCache<ClassLoader> classLoaderCache ) throws Throwable { _assert(TARGET != null, "environment variable TARGET not defined"); String nailgunTarget = cbtHome + "/" + NAILGUN + TARGET; 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, diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 7ff1f4b..889e32d 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -272,7 +272,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge the context is fresh on every complete run of cbt */ def cached[T <: AnyRef](name: String)(task: => T): T = { - val cache = context.taskCache + val cache = context.transientCache val key = (projectDirectory,name) if( cache.containsKey(key) ){ cache.get(key).asInstanceOf[T] diff --git a/stage2/Stage2.scala b/stage2/Stage2.scala index dfbead3..260a46d 100644 --- a/stage2/Stage2.scala +++ b/stage2/Stage2.scala @@ -31,8 +31,7 @@ object Stage2 extends Stage2Base{ logger.start, args.cbtHasChanged, null, - args.permanentKeys, - args.permanentClassLoaders, + args.persistentCache, new java.util.concurrent.ConcurrentHashMap, args.cache, args.cbtHome, diff --git a/stage2/ToolsTasks.scala b/stage2/ToolsTasks.scala index b96c8f2..b92cb7a 100644 --- a/stage2/ToolsTasks.scala +++ b/stage2/ToolsTasks.scala @@ -129,7 +129,7 @@ class EarlyDependencies{ ${files.map(d => s""" String ${valName(d)}File;""").mkString("\n")} public EarlyDependencies( - String mavenCache, String mavenUrl, ClassLoaderCache2<ClassLoader> classLoaderCache, ClassLoader rootClassLoader + String mavenCache, String mavenUrl, JavaCache<ClassLoader> classLoaderCache, ClassLoader rootClassLoader ) throws Throwable { ${files.map(d => s""" ${valName(d)}File = mavenCache + "${d.basePath(true)}.jar";""").mkString("\n")} diff --git a/test/test.scala b/test/test.scala index 0eb0bef..56ad3b1 100644 --- a/test/test.scala +++ b/test/test.scala @@ -115,8 +115,7 @@ object Main{ start, cbtHasChanged, null, - new ConcurrentHashMap[String,AnyRef], - new ConcurrentHashMap[AnyRef,ClassLoader], + new ConcurrentHashMap[AnyRef,AnyRef], new java.util.concurrent.ConcurrentHashMap[AnyRef,AnyRef], cache, cbtHome, |