-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Paralellize retrieving resolved packages #8220
base: main
Are you sure you want to change the base?
Conversation
) | ||
default: | ||
throw InternalError("invalid resolved package type \(resolvedPackage.packageRef.kind)") | ||
await withThrowingTaskGroup(of: Void.self) { taskGroup in |
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.
Returning back the parallelization of retrieving resolved packages
@@ -19,7 +19,7 @@ import SourceControl | |||
import struct TSCUtility.Version | |||
|
|||
/// Represents the workspace internal state persisted on disk. | |||
public final class WorkspaceState { | |||
public actor WorkspaceState { |
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.
Making WorkspaceState
into actor to make it thread-safe
@@ -172,12 +172,18 @@ extension Workspace.ManagedDependency: CustomStringConvertible { | |||
|
|||
extension Workspace { | |||
/// A collection of managed dependencies. | |||
final public class ManagedDependencies { | |||
public struct ManagedDependencies { |
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.
Turning ManagedDependencies
into a struct
. The alternative would be to make it an actor
but since it conforms to Collection
, it wouldn't be that easy.
There are only two methods of ManagedDependencies
that are mutable – add
and remove
. Instead of mutating self
, we can return copy of Self
and do the mutation in WorkspaceState
.
public func add(dependency: Workspace.ManagedDependency) { | ||
dependencies = dependencies.add(dependency) | ||
} | ||
|
||
public func remove(identity: PackageIdentity) { | ||
dependencies = dependencies.remove(identity) | ||
} |
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.
To keep the setter of dependencies
private
, we need to add helper methods for the two operations that mutate ManagedDependencies
. Alternatively, we could make the setter public, however, I do find this makes callsites of WorkspaceState
consumers nicer, so I'm leaning to keep the current solution.
I ran, from the root of the repository, the following shell script against this PR and there were no entries in the associated
|
Thanks for checking @bkhouri. I believe then the previous thread-safety issues should be fixed now 🙏 cc @dschaefer2 |
I added the utility script in #8227 |
Also, we did some performance testing of this branch at https://github.com/tuist/registry-tests using some real-world Here's some of the relevant data we gathered: Measurement dataPackage 1 (41 dependencies)Source control with Swift 6.0.3Source: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643543479#step:12:1276
Registry with Swift 6.0.3Source: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643544361#step:6:760
Source control using swift-package from this branchSource: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643543098#step:13:1006
Registry using swift-package from this branchSource: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643544096#step:11:514
Package 2 (63 dependencies)Source control with Swift 6.0.3Source: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643545273#step:12:3070
Registry with Swift 6.0.3Source: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643546221#step:6:2116
Source control using swift-package from this branchSource: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643544647#step:13:2614
Registry using swift-package from this branchSource: https://github.com/tuist/registry-tests/actions/runs/12785286884/job/35643545584#step:11:1750
|
@fortmarek Have you tried executing all of the swift tests on your change? Maybe it's me, but I'm seeing a few test failures when running |
Thanks @bkhouri! I don't think it has to do anything with running the tests in parallel, but some |
@bkhouri the issue should be fixed – |
Paralellize retrieving resolved packages
Motivation:
This PR brings back the parallelization reverted here.
As raised in the revertal, checkouts and registry downloads mutate the
WorkspaceState
– and running these operations in parallel can lead to a crash since theWorkspaceState
is not thread-safe.Modifications:
Based on this suggestion, I'm making
WorkspaceState
anactor
to make access to it thread-safe.Additionally, I turned
ManagedDependencies
into astruct
to ensure its thread-safety, too. There are two methods of this struct that mutate self –add
andremove
. I changed this to return a new copy ofManagedDependencies
instead and add counterpart methods inWorkspaceState
where the mutation is done in-place. SinceManagedDependencies
is aCollection
, making it into anactor
because of two mutable methods didn't feel like the right fit. However, let me know what you think about it.I added comments to the key modifications to make it easier to find the more interesting modifications since there's a lot of noise since I had to add loads of
async
andawait
. You can find these comments below.Result:
Retrieving resolved packages in parallel should not lead to crashes.
As suggested by @bkhouri here, I ran
WorkspaceTests
multiple times to see if I run into any thread-safety issues: