11package bloop .engine .tasks
22
3+ import java .nio .file .Path
34import java .util .Optional
5+ import java .util .concurrent .ConcurrentLinkedQueue
6+ import java .util .concurrent .atomic .AtomicInteger
7+
48import scala .collection .mutable
59import scala .concurrent .Promise
10+
611import bloop .CompileBackgroundTasks
712import bloop .CompileInputs
813import bloop .CompileOutPaths
@@ -35,17 +40,18 @@ import bloop.reporter.ReporterInputs
3540import bloop .task .Task
3641import bloop .tracing .BraveTracer
3742import bloop .util .BestEffortUtils .BestEffortProducts
43+
3844import monix .execution .CancelableFuture
3945import monix .reactive .MulticastStrategy
4046import monix .reactive .Observable
4147import xsbti .compile .CompileAnalysis
4248import xsbti .compile .MiniSetup
4349import xsbti .compile .PreviousResult
4450
45- import java .nio .file .Path
46-
4751object CompileTask {
4852 private implicit val logContext : DebugFilter = DebugFilter .Compilation
53+ private val compilationCounter = new AtomicInteger (0 )
54+ private val cleanUpTasks = new ConcurrentLinkedQueue [AbsolutePath ]()
4955
5056 def compile [UseSiteLogger <: Logger ](
5157 state : State ,
@@ -57,6 +63,8 @@ object CompileTask {
5763 store : CompileClientStore ,
5864 rawLogger : UseSiteLogger
5965 ): Task [State ] = Task .defer {
66+ compilationCounter.incrementAndGet()
67+
6068 import bloop .data .ClientInfo
6169 import bloop .internal .build .BuildInfo
6270 val originUri = state.build.origin
@@ -337,7 +345,7 @@ object CompileTask {
337345 }
338346
339347 val client = state.client
340- CompileGraph
348+ val compilation = CompileGraph
341349 .traverse(dag, client, store, bestEffortAllowed, setup, compile, tracer)
342350 .flatMap { pdag =>
343351 val partialResults = Dag .dfs(pdag, mode = Dag .PreOrder )
@@ -408,7 +416,12 @@ object CompileTask {
408416 .doOnFinish(_ => Task (rootTracer.terminate()))
409417 }
410418 }
419+ compilation
420+ .doOnFinish(_ =>
421+ cleanupIfNoCompilationRunning(compilationCounter.decrementAndGet(), tracer, rawLogger)
422+ )
411423 }
424+
412425 }
413426
414427 case class ConfiguredCompilation (scalacOptions : List [String ])
@@ -470,13 +483,14 @@ object CompileTask {
470483 for {
471484 _ <- previousSuccessful.populatingProducts
472485 _ <- populateNewProductsTask
473- _ <- cleanUpPreviousResult (
486+ toDelete = previousDirectoriesToCleanup (
474487 previousSuccessful,
475488 previousResult,
476489 compilerResult,
477490 tracer,
478491 logger
479492 )
493+ _ = toDelete.foreach(cleanUpTasks.add)
480494 } yield ()
481495 }
482496
@@ -514,15 +528,14 @@ object CompileTask {
514528 * superseeded by the new classes directory generated during a successful
515529 * compile.
516530 */
517- private def cleanUpPreviousResult (
531+ private def previousDirectoriesToCleanup (
518532 previousSuccessful : LastSuccessfulResult ,
519533 previousResult : Option [Compiler .Result ],
520534 compilerResult : Compiler .Result ,
521535 tracer : BraveTracer ,
522536 logger : Logger
523- ): Task [ Unit ] = tracer.trace(" clean up previous result" ) { implicit tracer =>
537+ ): List [ AbsolutePath ] = tracer.trace(" clean up previous result" ) { _ =>
524538 val previousClassesDir = previousSuccessful.classesDir
525- val currentlyUsedCounter = previousSuccessful.counterForClassesDir.decrementAndGet(1 )
526539
527540 val previousReadOnlyToDelete = compilerResult match {
528541 case Success (_, products, _, _, isNoOp, _, _) =>
@@ -532,11 +545,6 @@ object CompileTask {
532545 } else if (CompileOutPaths .hasEmptyClassesDir(previousClassesDir)) {
533546 logger.debug(s " Skipping delete of empty classes dir ${previousClassesDir}" )
534547 None
535- } else if (currentlyUsedCounter != 0 ) {
536- logger.debug(
537- s " Skipping delete of $previousClassesDir, counter is $currentlyUsedCounter"
538- )
539- None
540548 } else {
541549 val newClassesDir = products.newClassesDir
542550 logger.debug(s " Scheduling to delete ${previousClassesDir} superseded by $newClassesDir" )
@@ -566,28 +574,34 @@ object CompileTask {
566574 case _ => None
567575 }
568576
569- def deleteOrphanDir (orphanDir : Option [AbsolutePath ])(implicit
570- tracer : BraveTracer
571- ): Task [Unit ] = {
572- tracer.trace(" delete orphan dir" ) { _ =>
573- orphanDir match {
574- case None => Task .unit
575- case Some (classesDir) =>
577+ List (
578+ previousReadOnlyToDelete,
579+ previousBestEffortToDelete
580+ ).flatten
581+
582+ }
583+
584+ def cleanupIfNoCompilationRunning (
585+ counter : Int ,
586+ tracer : BraveTracer ,
587+ logger : Logger
588+ ): Task [Unit ] = {
589+ if (counter == 0 ) {
590+ tracer.trace(" delete orphan directories" ) { _ =>
591+ val allDeleteDirectories = new mutable.ListBuffer [AbsolutePath ]()
592+ while (cleanUpTasks.size() > 0 ) allDeleteDirectories += cleanUpTasks.poll()
593+ val allDeleteTasks = allDeleteDirectories
594+ .result()
595+ .map(classesDir => {
576596 Task .eval {
577- logger.debug(s " Deleting contents of orphan dir $classesDir" )
597+ logger.debug(s " Deleting contents of orphan dir $classesDir : ${classesDir.exists} " )
578598 BloopPaths .delete(classesDir)
579599 }.asyncBoundary
580- }
600+ })
601+ Task .gatherUnordered(allDeleteTasks).map(_ => ())
581602 }
603+ } else {
604+ Task .unit
582605 }
583-
584- Task
585- .gatherUnordered(
586- List (
587- deleteOrphanDir(previousReadOnlyToDelete),
588- deleteOrphanDir(previousBestEffortToDelete)
589- )
590- )
591- .map(_ => ())
592606 }
593607}
0 commit comments