Merge pull request #6001 from eatkins/evaluate-task-memory-leak

Fix EvaluateTask memory leak
This commit is contained in:
Ethan Atkins 2020-10-21 14:26:10 -07:00 committed by GitHub
commit f35675286b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 58 deletions

View File

@ -72,12 +72,15 @@ final case class State(
* @param currentExecId provide the execId extracted from the original State. * @param currentExecId provide the execId extracted from the original State.
* @param combinedParser the parser extracted from the original State. * @param combinedParser the parser extracted from the original State.
*/ */
@deprecated("unused", "1.4.2")
private[sbt] final case class SafeState( private[sbt] final case class SafeState(
currentExecId: Option[String], currentExecId: Option[String],
combinedParser: Parser[() => sbt.State] combinedParser: Parser[() => sbt.State]
) )
@deprecated("unused", "1.4.2")
private[sbt] object SafeState { private[sbt] object SafeState {
@deprecated("use StandardMain.exchange.withState", "1.4.2")
def apply(s: State) = { def apply(s: State) = {
new SafeState( new SafeState(
currentExecId = s.currentCommand.map(_.execId).flatten, currentExecId = s.currentCommand.map(_.execId).flatten,

View File

@ -413,9 +413,13 @@ object EvaluateTask {
(dummyRoots, roots) :: (Def.dummyStreamsManager, streams) :: (dummyState, state) :: dummies (dummyRoots, roots) :: (Def.dummyStreamsManager, streams) :: (dummyState, state) :: dummies
) )
@deprecated("use StandardMain.exchange.withState to obtain an instance of State", "1.4.2")
val lastEvaluatedState: AtomicReference[SafeState] = new AtomicReference() val lastEvaluatedState: AtomicReference[SafeState] = new AtomicReference()
@deprecated("use currentlyRunningTaskEngine", "1.4.2")
val currentlyRunningEngine: AtomicReference[(SafeState, RunningTaskEngine)] = val currentlyRunningEngine: AtomicReference[(SafeState, RunningTaskEngine)] =
new AtomicReference() new AtomicReference()
private[sbt] val currentlyRunningTaskEngine: AtomicReference[RunningTaskEngine] =
new AtomicReference()
/** /**
* The main method for the task engine. * The main method for the task engine.
@ -486,7 +490,7 @@ object EvaluateTask {
shutdownImpl(true) shutdownImpl(true)
} }
} }
currentlyRunningEngine.set((SafeState(state), runningEngine)) currentlyRunningTaskEngine.set(runningEngine)
// Register with our cancel handler we're about to start. // Register with our cancel handler we're about to start.
val strat = config.cancelStrategy val strat = config.cancelStrategy
val cancelState = strat.onTaskEngineStart(runningEngine) val cancelState = strat.onTaskEngineStart(runningEngine)
@ -494,8 +498,7 @@ object EvaluateTask {
try run() try run()
finally { finally {
strat.onTaskEngineFinish(cancelState) strat.onTaskEngineFinish(cancelState)
currentlyRunningEngine.set(null) currentlyRunningTaskEngine.set(null)
lastEvaluatedState.set(SafeState(state))
} }
} }

View File

@ -422,8 +422,7 @@ final class NetworkChannel(
protected def onCompletionRequest(execId: Option[String], cp: CompletionParams) = { protected def onCompletionRequest(execId: Option[String], cp: CompletionParams) = {
if (initialized) { if (initialized) {
try { try {
Option(EvaluateTask.lastEvaluatedState.get) match { StandardMain.exchange.withState { sstate =>
case Some(sstate) =>
import sbt.protocol.codec.JsonProtocol._ import sbt.protocol.codec.JsonProtocol._
def completionItems(s: State) = { def completionItems(s: State) = {
Parser Parser
@ -435,15 +434,14 @@ final class NetworkChannel(
} }
.map(c => cp.query + c) .map(c => cp.query + c)
} }
val (items, cachedMainClassNames, cachedTestNames) = StandardMain.exchange.withState { val (items, cachedMainClassNames, cachedTestNames) = {
s =>
val scopedKeyParser: Parser[Seq[Def.ScopedKey[_]]] = val scopedKeyParser: Parser[Seq[Def.ScopedKey[_]]] =
Act.aggregatedKeyParser(s) <~ Parsers.any.* Act.aggregatedKeyParser(sstate) <~ Parsers.any.*
Parser.parse(cp.query, scopedKeyParser) match { Parser.parse(cp.query, scopedKeyParser) match {
case Right(keys) => case Right(keys) =>
val testKeys = val testKeys =
keys.filter(k => k.key.label == "testOnly" || k.key.label == "testQuick") keys.filter(k => k.key.label == "testOnly" || k.key.label == "testQuick")
val (testState, cachedTestNames) = testKeys.foldLeft((s, true)) { val (testState, cachedTestNames) = testKeys.foldLeft((sstate, true)) {
case ((st, allCached), k) => case ((st, allCached), k) =>
SessionVar.loadAndSet(sbt.Keys.definedTestNames in k.scope, st, true) match { SessionVar.loadAndSet(sbt.Keys.definedTestNames in k.scope, st, true) match {
case (nst, d) => (nst, allCached && d.isDefined) case (nst, d) => (nst, allCached && d.isDefined)
@ -457,7 +455,7 @@ final class NetworkChannel(
} }
} }
(completionItems(runState), cachedMainClassNames, cachedTestNames) (completionItems(runState), cachedMainClassNames, cachedTestNames)
case _ => (completionItems(s), true, true) case _ => (completionItems(sstate), true, true)
} }
} }
respondResult( respondResult(
@ -468,12 +466,6 @@ final class NetworkChannel(
), ),
execId execId
) )
case _ =>
respondError(
ErrorCodes.UnknownError,
"No available sbt state",
execId
)
} }
} catch { } catch {
case NonFatal(_) => case NonFatal(_) =>
@ -498,9 +490,10 @@ final class NetworkChannel(
) )
try { try {
Option(EvaluateTask.currentlyRunningEngine.get) match { Option(EvaluateTask.currentlyRunningTaskEngine.get) match {
case Some((state, runningEngine)) => case Some(runningEngine) =>
val runningExecId = state.currentExecId.getOrElse("") val runningExecId =
StandardMain.exchange.withState(_.currentCommand.flatMap(_.execId).getOrElse(""))
val expected = StandardMain.exchange.withState( val expected = StandardMain.exchange.withState(
_.get(BasicCommands.execMap) _.get(BasicCommands.execMap)
.flatMap(s => s.get(crp.id) orElse s.get("\u2668" + crp.id)) .flatMap(s => s.get(crp.id) orElse s.get("\u2668" + crp.id))
@ -936,9 +929,10 @@ object NetworkChannel {
id: String id: String
): Either[String, String] = { ): Either[String, String] = {
Option(EvaluateTask.currentlyRunningEngine.get) match { Option(EvaluateTask.currentlyRunningTaskEngine.get) match {
case Some((state, runningEngine)) => case Some(runningEngine) =>
val runningExecId = state.currentExecId.getOrElse("") val runningExecId =
StandardMain.exchange.withState(_.currentCommand.flatMap(_.execId).getOrElse(""))
def checkId(): Boolean = { def checkId(): Boolean = {
if (runningExecId.startsWith("\u2668")) { if (runningExecId.startsWith("\u2668")) {