-
-
Notifications
You must be signed in to change notification settings - Fork 377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable lock on output dir for BSP server too #3683
Merged
lihaoyi
merged 6 commits into
com-lihaoyi:main
from
alexarchambault:out-global-lock-bsp
Oct 17, 2024
Merged
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0dc7764
Enable lock on output dir for BSP server too
alexarchambault a8a2067
fixup
alexarchambault 44b391d
Merge branch 'main' into pr/out-global-lock-bsp
alexarchambault c6e6bd1
Updates after merge
alexarchambault d322926
Revert everything
alexarchambault 0bc0f17
Lock via MillBuildServer
alexarchambault File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package mill.eval | ||
|
||
import mill.api.SystemStreams | ||
import mill.main.client.OutFiles | ||
import mill.main.client.lock.Lock | ||
|
||
import scala.util.Using | ||
|
||
object OutLock { | ||
|
||
def withLock[T]( | ||
noBuildLock: Boolean, | ||
noWaitForBuildLock: Boolean, | ||
out: os.Path, | ||
targetsAndParams: Seq[String], | ||
streams: SystemStreams | ||
)(t: => T): T = { | ||
if (noBuildLock) t | ||
else { | ||
val outLock = Lock.file((out / OutFiles.millLock).toString) | ||
|
||
def activeTaskString = | ||
try { | ||
os.read(out / OutFiles.millActiveCommand) | ||
} catch { | ||
case e => "<unknown>" | ||
} | ||
|
||
def activeTaskPrefix = s"Another Mill process is running '$activeTaskString'," | ||
Using.resource { | ||
val tryLocked = outLock.tryLock() | ||
if (tryLocked.isLocked()) tryLocked | ||
else if (noWaitForBuildLock) { | ||
throw new Exception(s"$activeTaskPrefix failing") | ||
} else { | ||
|
||
streams.err.println( | ||
s"$activeTaskPrefix waiting for it to be done..." | ||
) | ||
outLock.lock() | ||
} | ||
} { _ => | ||
os.write.over(out / OutFiles.millActiveCommand, targetsAndParams.mkString(" ")) | ||
try t | ||
finally os.remove.all(out / OutFiles.millActiveCommand) | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we keep the locking logic out of
Evaluator
? The granularity ofdef evaluate
is too fine grained, since we need to lock around not just a single evaluation but the entireMillBuildBootstrap
process that may encompass multiple evaluations.I'm actually not sure how the BSP server interacts with evaluators and the bootstrap process. Is it able to properly re-run bootstrapping if the build config changes from under it, or would it need to be explicitly restarted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe locking could be handled by the BSP server itself. It calls
evaluate
here or there, so the locking could be done around those calls.The BSP server is basically started on the side in
MillMain
(via theBspContext
), and gets all evaluators, for meta-builds and main build, via the"mill.bsp.BSP/startSession"
command (command that accepts anEvaluator.AllBootstrapEvaluators
to get the evaluators).That command is blocking, apparently to trigger reloads when clients ask for that. Maybe there's a way to make this command non-blocking, so that we can hold a lock too during the whole
MillBuildBootstrap
stuff that runs it…There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
In the short term, making the BSP server responsible for taking the lock whenever it calls
evaluate
sounds like a step forward: that is enough to ensure BSP evals do not overlap with CLI evals/bootstraps, even if it does not ensure BSP bootstraps overlap with CLI evals/bootstraps, but I assume that in any typical workflow there'll be a lot more BSP evals than there are BSP bootstrapsAfter that, medium term, let's see if there's some way to take the lock during the BSP bootstrap process as well, to ensure mutex between BSP bootstraps and CLI evals/bootstraps. I suspect doing it nicely may require refactoring how the BSP server is spawned and managed. I see two options:
Make BSP server go through
MillBuildBootstrap
every time it wants something, rather thanevaluate
.Make BSP server take the lock go through
MillBuildBoostrap#evaluate
only for generating theRunnerState
which contains the list of evaluators, then release the lock. After that, we can pass the evaluators to the BSP server, which can then take the lock as necessary when it calls evaluate on the bottom-most evaluatorOf the two options, maybe try (1) and see if we can make that work? And if not we can fall back to (2)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could try it, but I feel 1. would be impractical. Not having go through the meta-builds is actually a nice optimization.
To work around the issue you raise in 2.ii., I would try to avoid having a BSP server run on a stale meta-build as much as possible, but also find ways for it not crash if ever it does so.
To avoid having a BSP server run on a meta-build for too long, I'd make the command spawned for BSP in
MillMain
("mill.bsp.BSP/startSession"
) not block, so that the watch loop awakes as soon as the meta-build changes, and we can recompile the meta-build and update the evaluators ASAP. We could also prevent the BSP server from answering requests while the meta-build is being re-compiled.To prevent rare uses of a stale meta-build to crash with NoClassDefFound and the like, I'd copy the class path of a meta-build before creating a class loader with it. In a directory specific to that evaluator. So that when other evaluators re-compile the meta-build, they don't remove class files of class loaders of other evaluators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About that point, BSP has a notification for that, so that servers can notify clients that build targets were created / updated / deleted. Metals supports that, and Ammonite and Scala CLI notify Metals this way already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About this one, Bloop does things along those lines already: in
.bloop
sub-directories, it has its own directories with compilation output, but it copies it to distinct directories for each of its clients.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexarchambault what you proposed sounds reasonable, go for it