Skip to content

Commit 0ff8deb

Browse files
committed
.
1 parent e733461 commit 0ff8deb

12 files changed

Lines changed: 112 additions & 110 deletions

File tree

core/exec/src/mill/exec/Execution.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ case class Execution(
227227
)
228228

229229
val tracker = new Execution.LeaseTracker(indexToTerminal, interGroupDeps)
230-
def onTerminalCompleted(t: Task[?]): Unit = tracker.onCompleted(t)
231230
try {
232231

233232
def evaluateTerminals(
@@ -258,7 +257,7 @@ case class Execution(
258257
.map(t => (t, failure))
259258
.toMap
260259

261-
onTerminalCompleted(terminal)
260+
tracker.onCompleted(terminal)
262261
futures(terminal) = Future.successful(
263262
Some(GroupExecution.Results(
264263
newResults = taskResults,
@@ -365,7 +364,7 @@ case class Execution(
365364
nonFatal.setStackTrace(e.getStackTrace)
366365
throw nonFatal
367366
} finally {
368-
onTerminalCompleted(terminal)
367+
tracker.onCompleted(terminal)
369368
}
370369
}
371370
}
@@ -388,8 +387,8 @@ case class Execution(
388387
val exclusiveResults = evaluateTerminals(leafExclusiveCommands, exclusive = true)
389388

390389
// Set final header showing SUCCESS/FAILED status:
391-
// - FAILED: show for any outermost execution with failures
392-
// - SUCCESS: only show for the final requested depth
390+
// - FAILED: show for any outermost execution with failures (meta-build failures terminate bootstrapping)
391+
// - SUCCESS: only show for the final requested depth (depth 0 normally, or --meta-level if specified)
393392
val isOutermostExecution = executionNestingDepth.get() == 1
394393
val hasFailures = rootFailedCount.get() > 0
395394
val showFinalStatus = isOutermostExecution && (hasFailures || isFinalDepth)

core/internal/src/mill/internal/CrossThreadRwLock.scala

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,9 @@ class CrossThreadRwLock(label: String) {
2828

2929
private def waitingMessage(blocker: Option[HolderInfo]): String = blocker match {
3030
case Some(h) =>
31-
s"Another Mill command in the current daemon is running '${h.command}' with PID ${h.pid}"
31+
s"Another Mill command in the current daemon is running '${h.command}' task '$label' with PID ${h.pid}"
3232
case None =>
33-
s"Another Mill command in the current daemon is using '$label'"
34-
}
35-
36-
private def blockedSuffix(kind: LockKind): String = kind match {
37-
case LockKind.Read => s" (blocked on reading from $label)"
38-
case LockKind.Write => s" (blocked on writing to $label)"
33+
s"Another Mill command in the current daemon is using task '$label'"
3934
}
4035

4136
def acquire(
@@ -55,7 +50,7 @@ class CrossThreadRwLock(label: String) {
5550
Some(lease)
5651
} else if (noWait) {
5752
throw new Exception(
58-
s"${waitingMessage(currentBlocker())}${blockedSuffix(kind)} and --no-wait was set, failing"
53+
s"${waitingMessage(currentBlocker())} and --no-wait was set, failing"
5954
)
6055
} else {
6156
if (isWrite) waitingWriters += 1
@@ -66,9 +61,8 @@ class CrossThreadRwLock(label: String) {
6661
leaseOpt.getOrElse {
6762
val blocker = monitor.synchronized(currentBlocker())
6863
waitingErr.println(
69-
s"${waitingMessage(blocker)}, waiting for it to be done... " +
70-
s"(tail -F out/${DaemonFiles.millConsoleTail} to see its progress)" +
71-
blockedSuffix(kind)
64+
s"${waitingMessage(blocker)}, waiting for it " +
65+
s"(tail -F out/${DaemonFiles.millConsoleTail} to see its progress)"
7266
)
7367

7468
monitor.synchronized {

core/internal/src/mill/internal/LauncherOutFilesImpl.scala

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,37 @@ private[mill] class LauncherOutFilesImpl(
1111
out: os.Path,
1212
activeCommandMessage: String,
1313
launcherPid: Long,
14-
artifactState: LauncherArtifactState,
14+
outFilesState: LauncherOutFilesState,
1515
private val runId: String
1616
) extends LauncherOutFiles {
1717
import LauncherOutFilesImpl.*
1818

19-
private val runDir = out / LauncherArtifactState.runRootDirName / runId
19+
private val runDir = out / LauncherOutFilesState.runRootDirName / runId
2020
override val consoleTail: java.nio.file.Path = (runDir / "mill-console-tail").toNIO
2121
override val profile: java.nio.file.Path = (runDir / OutFiles.millProfile).toNIO
2222
override val chromeProfile: java.nio.file.Path = (runDir / OutFiles.millChromeProfile).toNIO
2323
override val dependencyTree: java.nio.file.Path = (runDir / OutFiles.millDependencyTree).toNIO
2424
override val invalidationTree: java.nio.file.Path = (runDir / OutFiles.millInvalidationTree).toNIO
2525
private val closed = new AtomicBoolean(false)
2626

27-
private val publishedArtifacts = Seq(
28-
PublishedArtifact(
27+
private val publishedOutFiles = Seq(
28+
PublishedOutFile(
2929
out / DaemonFiles.millConsoleTail,
3030
os.Path(consoleTail),
3131
copyFallback = false
3232
),
33-
PublishedArtifact(out / OutFiles.millProfile, os.Path(profile), copyFallback = true),
34-
PublishedArtifact(
33+
PublishedOutFile(out / OutFiles.millProfile, os.Path(profile), copyFallback = true),
34+
PublishedOutFile(
3535
out / OutFiles.millChromeProfile,
3636
os.Path(chromeProfile),
3737
copyFallback = true
3838
),
39-
PublishedArtifact(
39+
PublishedOutFile(
4040
out / OutFiles.millDependencyTree,
4141
os.Path(dependencyTree),
4242
copyFallback = true
4343
),
44-
PublishedArtifact(
44+
PublishedOutFile(
4545
out / OutFiles.millInvalidationTree,
4646
os.Path(invalidationTree),
4747
copyFallback = true
@@ -55,29 +55,29 @@ private[mill] class LauncherOutFilesImpl(
5555
// for deletion, so the record must be visible before the directory exists.
5656
writeLauncherRunFile()
5757
os.makeDir.all(runDir)
58-
cleanup(out, artifactState)
58+
cleanup(out, outFilesState)
5959

6060
override def publishLiveArtifacts(): Unit =
61-
if (!closed.get()) publishLatest(publishedArtifacts.head, artifactState)
61+
if (!closed.get()) publishLatest(publishedOutFiles.head, outFilesState)
6262

6363
override def publishArtifacts(): Unit =
64-
if (!closed.get()) publishedArtifacts.foreach(publishLatest(_, artifactState))
64+
if (!closed.get()) publishedOutFiles.foreach(publishLatest(_, outFilesState))
6565

6666
override def close(): Unit =
6767
if (closed.compareAndSet(false, true)) {
68-
LauncherRecordStore.remove(out, runId)
69-
cleanup(out, artifactState)
68+
LauncherOutFilesRecordStore.remove(out, runId)
69+
cleanup(out, outFilesState)
7070
}
7171

7272
private def writeLauncherRunFile(): Unit =
73-
LauncherRecordStore.write(out, runId, launcherPid, activeCommandMessage)
73+
LauncherOutFilesRecordStore.write(out, runId, launcherPid, activeCommandMessage)
7474
}
7575

7676
private[mill] object LauncherOutFilesImpl {
7777
private val maxRetainedRuns = 10
78-
private case class PublishedArtifact(link: os.Path, target: os.Path, copyFallback: Boolean)
78+
private case class PublishedOutFile(link: os.Path, target: os.Path, copyFallback: Boolean)
7979

80-
private val wellKnownArtifactLinks = Seq(
80+
private val wellKnownOutFileLinks = Seq(
8181
os.RelPath(DaemonFiles.millConsoleTail),
8282
os.RelPath(OutFiles.millProfile),
8383
os.RelPath(OutFiles.millChromeProfile),
@@ -99,11 +99,11 @@ private[mill] object LauncherOutFilesImpl {
9999

100100
private def cleanup(
101101
out: os.Path,
102-
artifactState: LauncherArtifactState
102+
outFilesState: LauncherOutFilesState
103103
): Unit = {
104104
try {
105-
val active = LauncherRecordStore.sweepActive(out).iterator.map(_.runId).toSet
106-
val runRootDir = out / LauncherArtifactState.runRootDirName
105+
val active = LauncherOutFilesRecordStore.sweepActive(out).iterator.map(_.runId).toSet
106+
val runRootDir = out / LauncherOutFilesState.runRootDirName
107107
if (os.exists(runRootDir)) {
108108
val runDirs = os.list(runRootDir).filter(os.isDir(_))
109109
val eligible = runDirs.filterNot(d => active.contains(d.last)).sortBy(runDirSortKey)
@@ -114,9 +114,9 @@ private[mill] object LauncherOutFilesImpl {
114114
)
115115
}
116116

117-
wellKnownArtifactLinks.foreach { rel =>
117+
wellKnownOutFileLinks.foreach { rel =>
118118
val link = out / rel
119-
withArtifactLock(link, artifactState) {
119+
withPublishedPathLock(link, outFilesState) {
120120
if (os.isLink(link) && !os.exists(link, followLinks = true)) {
121121
try os.remove(link)
122122
catch { case _: Throwable => () }
@@ -126,12 +126,12 @@ private[mill] object LauncherOutFilesImpl {
126126
} catch { case _: Throwable => () }
127127
}
128128

129-
private def withArtifactLock[T](
129+
private def withPublishedPathLock[T](
130130
link: os.Path,
131-
artifactState: LauncherArtifactState
131+
outFilesState: LauncherOutFilesState
132132
)(body: => T): T = {
133133
val key = link.toNIO.toAbsolutePath.normalize.toString
134-
artifactState.artifactLockFor(key).synchronized(body)
134+
outFilesState.publishedPathLockFor(key).synchronized(body)
135135
}
136136

137137
private def replaceAtomically(
@@ -159,40 +159,40 @@ private[mill] object LauncherOutFilesImpl {
159159
private def updateSymlink(
160160
link: os.Path,
161161
target: os.Path,
162-
artifactState: LauncherArtifactState
162+
outFilesState: LauncherOutFilesState
163163
): Unit = {
164164
val rel = relativizeTarget(link, target)
165165
replaceAtomically(
166166
link,
167-
s".${link.last}.tmp-${System.nanoTime()}-${artifactState.nextTmpSuffix()}"
167+
s".${link.last}.tmp-${System.nanoTime()}-${outFilesState.nextTmpSuffix()}"
168168
)(tmp => os.symlink(tmp, rel))
169169
}
170170

171171
private def replaceWithCopy(
172172
link: os.Path,
173173
target: os.Path,
174-
artifactState: LauncherArtifactState
174+
outFilesState: LauncherOutFilesState
175175
): Unit = {
176176
replaceAtomically(
177177
link,
178-
s".${link.last}.copy-${System.nanoTime()}-${artifactState.nextTmpSuffix()}"
178+
s".${link.last}.copy-${System.nanoTime()}-${outFilesState.nextTmpSuffix()}"
179179
)(tmp => os.copy.over(target, tmp, createFolders = true))
180180
}
181181

182182
private def publishLatest(
183-
artifact: PublishedArtifact,
184-
artifactState: LauncherArtifactState
183+
outFile: PublishedOutFile,
184+
outFilesState: LauncherOutFilesState
185185
): Unit = {
186-
withArtifactLock(artifact.link, artifactState) {
187-
if (os.exists(artifact.target))
188-
try updateSymlink(artifact.link, artifact.target, artifactState)
186+
withPublishedPathLock(outFile.link, outFilesState) {
187+
if (os.exists(outFile.target))
188+
try updateSymlink(outFile.link, outFile.target, outFilesState)
189189
catch {
190190
case e: Throwable =>
191191
mill.api.Debug(
192-
s"Failed to publish ${artifact.link.last} as a symlink: ${e.getClass.getSimpleName}: ${e.getMessage}"
192+
s"Failed to publish ${outFile.link.last} as a symlink: ${e.getClass.getSimpleName}: ${e.getMessage}"
193193
)
194-
if (artifact.copyFallback)
195-
replaceWithCopy(artifact.link, artifact.target, artifactState)
194+
if (outFile.copyFallback)
195+
replaceWithCopy(outFile.link, outFile.target, outFilesState)
196196
}
197197
}
198198
}

core/internal/src/mill/internal/LauncherRecordStore.scala renamed to core/internal/src/mill/internal/LauncherOutFilesRecordStore.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import mill.constants.DaemonFiles
44

55
import scala.jdk.OptionConverters.RichOptional
66

7-
private[mill] object LauncherRecordStore {
7+
private[mill] object LauncherOutFilesRecordStore {
88
case class Record(runId: String, pid: Long, command: String)
99

1010
def path(out: os.Path, runId: String): os.Path =

core/internal/src/mill/internal/LauncherArtifactState.scala renamed to core/internal/src/mill/internal/LauncherOutFilesState.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import mill.constants.DaemonFiles
55
import java.util.concurrent.ConcurrentHashMap
66
import java.util.concurrent.atomic.AtomicLong
77

8-
private[mill] class LauncherArtifactState {
9-
private val artifactLocks = new ConcurrentHashMap[String, AnyRef]()
8+
private[mill] class LauncherOutFilesState {
9+
private val publishedPathLocks = new ConcurrentHashMap[String, AnyRef]()
1010
private val runIdCounter = new AtomicLong(0L)
1111
private val tmpNameCounter = new AtomicLong(0L)
1212
// The PR design allows a MillNoDaemonMain process to share `out/` with a
@@ -15,15 +15,15 @@ private[mill] class LauncherArtifactState {
1515
// run directories and launcher record files cannot collide across processes.
1616
private val pid: Long = ProcessHandle.current().pid()
1717

18-
def artifactLockFor(normalizedAbsolutePath: String): AnyRef =
19-
artifactLocks.computeIfAbsent(normalizedAbsolutePath, _ => new Object)
18+
def publishedPathLockFor(normalizedAbsolutePath: String): AnyRef =
19+
publishedPathLocks.computeIfAbsent(normalizedAbsolutePath, _ => new Object)
2020

2121
def nextRunId(): String =
2222
s"${System.currentTimeMillis()}-$pid-${runIdCounter.getAndIncrement()}"
2323

2424
def nextTmpSuffix(): Long = tmpNameCounter.getAndIncrement()
2525
}
2626

27-
private[mill] object LauncherArtifactState {
27+
private[mill] object LauncherOutFilesState {
2828
val runRootDirName = DaemonFiles.millRun
2929
}

core/internal/test/src/mill/internal/CrossThreadRwLockTests.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,9 @@ object CrossThreadRwLockTests extends TestSuite {
287287
assertEventually(waitingBytes.size() > 0)
288288
val msg = waitingBytes.toString
289289
assert(msg.contains("'blockerTask'"))
290+
assert(msg.contains("task 'holder-naming'"))
290291
assert(msg.contains("PID 9876"))
291-
assert(msg.contains("waiting for it to be done..."))
292+
assert(msg.contains("waiting for it (tail -F out/mill-console-tail to see its progress)"))
292293

293294
firstLease.close()
294295
assert(secondAcquired.await(5, TimeUnit.SECONDS))
@@ -346,6 +347,7 @@ object CrossThreadRwLockTests extends TestSuite {
346347
case e: Exception => e
347348
}
348349
assert(ex.getMessage.contains("'blockerCmd'"))
350+
assert(ex.getMessage.contains("task 'no-wait'"))
349351
assert(ex.getMessage.contains("PID 7777"))
350352
assert(ex.getMessage.contains("--no-wait"))
351353

@@ -376,6 +378,7 @@ object CrossThreadRwLockTests extends TestSuite {
376378
assertEventually(waitingBytes.size() > 0)
377379
val msg = waitingBytes.toString
378380
assert(msg.contains("'stillHoldingCmd'"))
381+
assert(msg.contains("task 'stale-last-holder'"))
379382
assert(msg.contains("PID 1111"))
380383
assert(!msg.contains("'alreadyReleasedCmd'"))
381384
assert(!msg.contains("PID 2222"))

core/internal/test/src/mill/internal/LauncherOutFilesImplTests.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,24 @@ object LauncherOutFilesImplTests extends TestSuite {
88
test("cleanupDoesNotDeleteJustFinishedRunWhenActiveRunsFillRetention") {
99
val out = os.temp.dir(prefix = "mill-launcher-out-files")
1010
try {
11-
val artifactState = new LauncherArtifactState
11+
val outFilesState = new LauncherOutFilesState
1212
val pid = ProcessHandle.current().pid()
1313

1414
for (i <- 0 until 10) {
1515
val runId = s"1000-$pid-$i"
16-
LauncherRecordStore.write(out, runId, pid, s"active-$i")
17-
os.makeDir.all(out / LauncherArtifactState.runRootDirName / runId)
16+
LauncherOutFilesRecordStore.write(out, runId, pid, s"active-$i")
17+
os.makeDir.all(out / LauncherOutFilesState.runRootDirName / runId)
1818
}
1919

2020
val finishedRunId = s"2000-$pid-0"
2121
val outFiles = new LauncherOutFilesImpl(
2222
out = out,
2323
activeCommandMessage = "finished",
2424
launcherPid = pid,
25-
artifactState = artifactState,
25+
outFilesState = outFilesState,
2626
runId = finishedRunId
2727
)
28-
val finishedRunDir = out / LauncherArtifactState.runRootDirName / finishedRunId
28+
val finishedRunDir = out / LauncherOutFilesState.runRootDirName / finishedRunId
2929
os.write(os.Path(outFiles.profile), "[]", createFolders = true)
3030
outFiles.publishArtifacts()
3131
outFiles.close()
@@ -39,10 +39,10 @@ object LauncherOutFilesImplTests extends TestSuite {
3939
val out = os.temp.dir(prefix = "mill-launcher-records")
4040
try {
4141
val runId = "1000-123-0"
42-
val record = LauncherRecordStore.path(out, runId)
42+
val record = LauncherOutFilesRecordStore.path(out, runId)
4343
os.write.over(record, "{", createFolders = true)
4444

45-
val active = LauncherRecordStore.sweepActive(out)
45+
val active = LauncherOutFilesRecordStore.sweepActive(out)
4646

4747
assert(active.exists(_.runId == runId))
4848
assert(os.exists(record))

0 commit comments

Comments
 (0)