diff --git a/ivy/src/main/scala/sbt/JsonUtil.scala b/ivy/src/main/scala/sbt/JsonUtil.scala index 88d7e1e90..156c9aa44 100644 --- a/ivy/src/main/scala/sbt/JsonUtil.scala +++ b/ivy/src/main/scala/sbt/JsonUtil.scala @@ -25,8 +25,34 @@ private[sbt] object JsonUtil { } def toLite(ur: UpdateReport): UpdateReportLite = UpdateReportLite(ur.configurations map { cr => - ConfigurationReportLite(cr.configuration, cr.details) + ConfigurationReportLite(cr.configuration, cr.details map { oar => + new OrganizationArtifactReport(oar.organization, oar.name, oar.modules map { mr => + new ModuleReport( + mr.module, mr.artifacts, mr.missingArtifacts, mr.status, + mr.publicationDate, mr.resolver, mr.artifactResolver, + mr.evicted, mr.evictedData, mr.evictedReason, + mr.problem, mr.homepage, mr.extraAttributes, + mr.isDefault, mr.branch, mr.configurations, mr.licenses, + summarizeCallers(mr.callers)) + }) + }) }) + // #1763/#2030. Caller takes up 97% of space, so we need to shrink it down, + // but there are semantics associated with some of them. + def summarizeCallers(callers: Seq[Caller]): Seq[Caller] = + if (callers.isEmpty) callers + else { + // Use the first element to represent all callers + val head = callers.head + val caller = new Caller( + head.caller, head.callerConfigurations, head.callerExtraAttributes, + callers exists { _.isForceDependency }, + callers exists { _.isChangingDependency }, + callers exists { _.isTransitiveDependency }, + callers exists { _.isDirectlyForceDependency }) + Seq(caller) + } + def fromLite(lite: UpdateReportLite, cachedDescriptor: File): UpdateReport = { val stats = new UpdateStats(0L, 0L, 0L, false) diff --git a/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala b/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala index 14d7af22a..5b0418abf 100644 --- a/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala +++ b/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala @@ -25,7 +25,7 @@ private[sbt] object CachedResolutionResolveCache { def createID(organization: String, name: String, revision: String) = ModuleRevisionId.newInstance(organization, name, revision) def sbtOrgTemp = "org.scala-sbt.temp" - def graphVersion = "0.13.8" + def graphVersion = "0.13.9" } private[sbt] class CachedResolutionResolveCache() { diff --git a/notes/0.13.9/cached-resolution-fix.markdown b/notes/0.13.9/cached-resolution-fix.markdown new file mode 100644 index 000000000..ad439b2da --- /dev/null +++ b/notes/0.13.9/cached-resolution-fix.markdown @@ -0,0 +1,26 @@ + [@cunei]: https://github.com/cunei + [@eed3si9n]: https://github.com/eed3si9n + [@gkossakowski]: https://github.com/gkossakowski + [@jsuereth]: https://github.com/jsuereth + + [1721]: https://github.com/sbt/sbt/issues/1721 + [2030]: https://github.com/sbt/sbt/pull/2030 + +### Fixes with compatibility implications + +### Improvements + +### Bug fixes + +- Fixes memory/performance issue with cached resolution. See below. + +### Cached resolution fixes + +On a larger dependency graph, the JSON file growing to be 100MB+ +with 97% of taken up by *caller* information. +The caller information is not useful once the graph is successfully resolved. +sbt 0.13.9 creates a single caller to represent all callers, +which fixes `OutOfMemoryException` seen on some builds, +and generally it should make JSON IO faster. + +[#2030][2030]/[#1721][1721] by [@eed3si9n][@eed3si9n]