From 4185639097f8dc546c6474095c1fe853d43a1069 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Sun, 19 Mar 2017 20:03:08 -0400 Subject: performance tweak: cache results of parsed pom files in memory --- stage1/Stage1Lib.scala | 46 +++++++++++++++++++++++++++++++--------------- stage1/resolver.scala | 13 ++++++++++--- 2 files changed, 41 insertions(+), 18 deletions(-) (limited to 'stage1') diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 9e6f6b0..3ffc878 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -310,23 +310,39 @@ ${sourceFiles.sorted.mkString(" \\\n")} groupId, artifactId ++ "_" ++ scalaMajorVersion, version, classifier, verifyHash ) - def cacheOnDisk[T] - ( cbtLastModified: Long, cacheFile: File ) + def cacheOnDisk[T,J <: AnyRef : scala.reflect.ClassTag] + ( cbtLastModified: Long, cacheFile: File, persistentCache: java.util.Map[AnyRef,AnyRef] ) ( deserialize: String => T ) ( serialize: T => String ) - ( compute: => Seq[T] ) = { - if(cacheFile.exists && cacheFile.lastModified > cbtLastModified ){ - import collection.JavaConversions._ - Files - .readAllLines( cacheFile.toPath, StandardCharsets.UTF_8 ) - .toStream - .map(deserialize) - } else { - val result = compute - val string = result.map(serialize).mkString("\n") - write(cacheFile, string) - result - } + ( dejavafy: J => Seq[T] ) + ( javafy: Seq[T] => J ) + ( compute: => Seq[T] ): Seq[T] = { + val key = "cacheOnDisk:" + cacheFile + Option( persistentCache.get(key) ).map( + _.asInstanceOf[Array[AnyRef]] + ).map{ + case Array(time: java.lang.Long, javafied: J) => (time, javafied) + }.filter( _._1 > cbtLastModified ) + .map( _._2 ) + .map( dejavafy ) + .orElse{ + (cacheFile.exists && cacheFile.lastModified > cbtLastModified).option{ + import collection.JavaConversions._ + val v = Files + .readAllLines( cacheFile.toPath, StandardCharsets.UTF_8 ) + .toStream + .map( deserialize ) + persistentCache.put(key, Array(System.currentTimeMillis:java.lang.Long, javafy(v))) + v + } + }.getOrElse{ + val result = compute + val strings = result.map(serialize) + val string = strings.mkString("\n") + write(cacheFile, string) + persistentCache.put(key, Array(System.currentTimeMillis:java.lang.Long, javafy(result))) + result + } } def dependencyTreeRecursion(root: Dependency, indent: Int = 0): String = ( diff --git a/stage1/resolver.scala b/stage1/resolver.scala index 6c31a98..1293a89 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -213,12 +213,19 @@ abstract class DependenciesProxy{ case class MavenDependency( groupId: String, artifactId: String, version: String, classifier: Classifier = Classifier.none, verifyHash: Boolean = true ){ - private[cbt] def serialize = groupId ++ ":" ++ artifactId ++ ":"++ version ++ classifier.name.map(":" ++ _).getOrElse("") + private[cbt] def serialize = // PERFORMANCE HOTSPOT + groupId + ":" + artifactId + ":" + version + ( if(classifier.name.nonEmpty) ":" + classifier.name.get else "" ) + private[cbt] def javafy: Array[String] = + Array(groupId,artifactId,version) ++ classifier.name } object MavenDependency{ private[cbt] def deserialize = (_:String).split(":") match { case col => MavenDependency( col(0), col(1), col(2), Classifier(col.lift(3)) ) } + private[cbt] def dejavafy = + ( cols:Array[Array[String]] ) => cols.map( + col => MavenDependency( col(0), col(1), col(2), Classifier(col.lift(3)) ) + ).toSeq } // FIXME: take MavenResolver instead of mavenCache and repositories separately case class BoundMavenDependency( @@ -338,8 +345,8 @@ case class BoundMavenDependency( if(classifier == Classifier.sources) Seq() else { lib.cacheOnDisk( - cbtLastModified, mavenCache ++ basePath(true) ++ ".pom.dependencies" - )( MavenDependency.deserialize )( _.serialize ){ + cbtLastModified, mavenCache ++ basePath(true) ++ ".pom.dependencies", classLoaderCache.hashMap + )( MavenDependency.deserialize )( _.serialize )( MavenDependency.dejavafy )( _.map(_.javafy).toArray ){ (pomXml \ "dependencies" \ "dependency").collect{ case xml if ( (xml \ "scope").text == "" || (xml \ "scope").text == "compile" ) && (xml \ "optional").text != "true" => val artifactId = lookup(xml,_ \ "artifactId").get -- cgit v1.2.3