Skip to content

Change from Lock wrapper inside TSCBasic to NSLock #5575

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

Merged
merged 4 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Sources/Basics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_library(Basics
JSON+Extensions.swift
JSONDecoder+Extensions.swift
Netrc.swift
NSLock+Extensions.swift
Observability.swift
Sandbox.swift
String+Extensions.swift
Expand Down
12 changes: 6 additions & 6 deletions Sources/Basics/ConcurrencyHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
//===----------------------------------------------------------------------===//

import Dispatch
import class Foundation.NSLock
import class Foundation.ProcessInfo
import TSCBasic

public typealias Lock = TSCBasic.Lock
import enum TSCBasic.ProcessEnv
import func TSCBasic.tsc_await

/// Thread-safe dictionary like structure
public final class ThreadSafeKeyValueStore<Key, Value> where Key: Hashable {
private var underlying: [Key: Value]
private let lock = Lock()
private let lock = NSLock()

public init(_ seed: [Key: Value] = [:]) {
self.underlying = seed
Expand Down Expand Up @@ -100,7 +100,7 @@ public final class ThreadSafeKeyValueStore<Key, Value> where Key: Hashable {
/// Thread-safe array like structure
public final class ThreadSafeArrayStore<Value> {
private var underlying: [Value]
private let lock = Lock()
private let lock = NSLock()

public init(_ seed: [Value] = []) {
self.underlying = seed
Expand Down Expand Up @@ -172,7 +172,7 @@ public final class ThreadSafeArrayStore<Value> {
@dynamicMemberLookup
public final class ThreadSafeBox<Value> {
private var underlying: Value?
private let lock = Lock()
private let lock = NSLock()

public init() {}

Expand Down
3 changes: 2 additions & 1 deletion Sources/Basics/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import struct Foundation.Data
import struct Foundation.Date
import class Foundation.JSONDecoder
import class Foundation.NSError
import class Foundation.NSLock
import class Foundation.OperationQueue
import struct Foundation.URL
import struct Foundation.UUID
Expand Down Expand Up @@ -56,7 +57,7 @@ public struct HTTPClient: Cancellable {
private var outstandingRequests = ThreadSafeKeyValueStore<UUID, (url: URL, completion: CompletionHandler, progress: ProgressHandler?, queue: DispatchQueue)>()

// static to share across instances of the http client
private static var hostsErrorsLock = Lock()
private static var hostsErrorsLock = NSLock()
private static var hostsErrors = [String: [Date]]()

public init(configuration: HTTPClientConfiguration = .init(), handler: Handler? = nil) {
Expand Down
20 changes: 20 additions & 0 deletions Sources/Basics/NSLock+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import class Foundation.NSLock

extension NSLock {
/// Execute the given block while holding the lock.
public func withLock<T> (_ body: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try body()
}
}
2 changes: 1 addition & 1 deletion Sources/Basics/SQLiteBackedCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public final class SQLiteBackedCache<Value: Codable>: Closable {
public let configuration: SQLiteBackedCacheConfiguration

private var state = State.idle
private let stateLock = Lock()
private let stateLock = NSLock()

private let jsonEncoder: JSONEncoder
private let jsonDecoder: JSONDecoder
Expand Down
3 changes: 2 additions & 1 deletion Sources/Commands/SwiftTestTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ArgumentParser
import Basics
import Build
import Dispatch
import class Foundation.NSLock
import class Foundation.ProcessInfo
import PackageGraph
import PackageModel
Expand Down Expand Up @@ -769,7 +770,7 @@ final class ParallelTestRunner {
observabilityScope: self.observabilityScope
)
var output = ""
let outputLock = Lock()
let outputLock = NSLock()
let start = DispatchTime.now()
let success = testRunner.test(outputHandler: { _output in outputLock.withLock{ output += _output }})
let duration = start.distance(to: .now())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Dispatch
import struct Foundation.Data
import class Foundation.JSONDecoder
import class Foundation.JSONEncoder
import class Foundation.NSLock
import struct Foundation.URL
import PackageModel
import TSCBasic
Expand All @@ -36,22 +37,22 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
private let decoder: JSONDecoder

private var state = State.idle
private let stateLock = Lock()
private let stateLock = NSLock()

private let cache = ThreadSafeKeyValueStore<Model.CollectionIdentifier, Model.Collection>()

// Lock helps prevent concurrency errors with transaction statements during e.g. `refreshCollections`,
// NSLock helps prevent concurrency errors with transaction statements during e.g. `refreshCollections`,
// since only one transaction is allowed per SQLite connection. We need transactions to speed up bulk updates.
// TODO: we could potentially optimize this with db connection pool
private let ftsLock = Lock()
private let ftsLock = NSLock()
// FTS not supported on some platforms; the code falls back to "slow path" in that case
// marked internal for testing
internal let useSearchIndices = ThreadSafeBox<Bool>()

// Targets have in-memory trie in addition to SQLite FTS as optimization
private let targetTrie = Trie<CollectionPackage>()
private var targetTrieReady: Bool?
private let populateTargetTrieLock = Lock()
private let populateTargetTrieLock = NSLock()

init(location: SQLite.Location? = nil, configuration: Configuration = .init(), observabilityScope: ObservabilityScope) {
self.location = location ?? .path(localFileSystem.swiftPMCacheDirectory.appending(components: "package-collection.db"))
Expand Down
9 changes: 4 additions & 5 deletions Sources/PackageCollections/Storage/Trie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
//
//===----------------------------------------------------------------------===//

import TSCBasic

import class Foundation.NSLock
import PackageModel

struct Trie<Document: Hashable> {
private typealias Node = TrieNode<Character, Document>

private let root: Node
private let lock = Lock()
private let lock = NSLock()

init() {
self.root = Node()
Expand Down Expand Up @@ -183,11 +182,11 @@ private final class TrieNode<T: Hashable, Document: Hashable> {

/// The children of this node identified by their corresponding value.
private var _children = [T: TrieNode<T, Document>]()
private let childrenLock = Lock()
private let childrenLock = NSLock()

/// If the path to this node forms a valid word, these are the documents where the word can be found.
private var _documents = Set<Document>()
private let documentsLock = Lock()
private let documentsLock = NSLock()

var isLeaf: Bool {
self.childrenLock.withLock {
Expand Down
2 changes: 1 addition & 1 deletion Sources/PackageGraph/DependencyMirrors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public final class DependencyMirrors: Equatable {
private var index: [String: String]
private var reverseIndex: [String: [String]]
private var visited: OrderedCollections.OrderedSet<String>
private let lock = Lock()
private let lock = NSLock()

public var mapping: [String: String] {
self.lock.withLock {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import Basics
import Dispatch
import class Foundation.NSLock
import OrderedCollections
import PackageModel
import TSCBasic
Expand Down Expand Up @@ -39,7 +40,7 @@ public struct PubgrubDependencyResolver {
/// The current best guess for a solution satisfying all requirements.
public private(set) var solution: PartialSolution

private let lock = Lock()
private let lock = NSLock()

init(root: DependencyResolutionNode,
overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)] = [:],
Expand Down
2 changes: 1 addition & 1 deletion Sources/SPMTestSupport/InMemoryGitRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public final class InMemoryGitRepository {
/// The file system in which this repository should be installed.
private let fs: InMemoryFileSystem

private let lock = Lock()
private let lock = NSLock()

/// Create a new repository at the given path and filesystem.
public init(path: AbsolutePath, fs: InMemoryFileSystem) {
Expand Down
4 changes: 2 additions & 2 deletions Sources/SPMTestSupport/MockPackageFingerprintStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

import Basics
import Dispatch
import class Foundation.NSLock
import PackageFingerprint
import PackageModel
import TSCBasic

public class MockPackageFingerprintStorage: PackageFingerprintStorage {
private var packageFingerprints: [PackageIdentity: [Version: [Fingerprint.Kind: Fingerprint]]]
private let lock = Lock()
private let lock = NSLock()

public init(_ packageFingerprints: [PackageIdentity: [Version: [Fingerprint.Kind: Fingerprint]]] = [:]) {
self.packageFingerprints = packageFingerprints
Expand Down
2 changes: 1 addition & 1 deletion Sources/SPMTestSupport/MockRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class MockRegistry {
private var packageVersions = [PackageIdentity: [String: InMemoryRegistryPackageSource]]()
private var packagesSourceControlURLs = [PackageIdentity: [URL]]()
private var sourceControlURLs = [URL: PackageIdentity]()
private let packagesLock = Lock()
private let packagesLock = NSLock()

public init(
filesystem: FileSystem,
Expand Down
2 changes: 1 addition & 1 deletion Sources/SPMTestSupport/MockWorkspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ public final class MockWorkspace {
}

public final class MockWorkspaceDelegate: WorkspaceDelegate {
private let lock = Lock()
private let lock = NSLock()
private var _events = [String]()
private var _manifest: Manifest?
private var _manifestLoadingDiagnostics: [Basics.Diagnostic]?
Expand Down
1 change: 0 additions & 1 deletion Sources/SPMTestSupport/Observability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//

import Basics
import struct TSCBasic.Lock
import struct TSCBasic.StringError
import func XCTest.XCTFail
import func XCTest.XCTAssertEqual
Expand Down
3 changes: 2 additions & 1 deletion Sources/SourceControl/GitRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import Basics
import Dispatch
import class Foundation.NSLock
import TSCBasic

import enum TSCUtility.Git
Expand Down Expand Up @@ -331,7 +332,7 @@ public final class GitRepository: Repository, WorkingCheckout {
private let git: GitShellHelper

// lock top protect concurrent modifications to the repository
private let lock = Lock()
private let lock = NSLock()

/// If this repo is a work tree repo (checkout) as opposed to a bare repo.
private let isWorkingRepo: Bool
Expand Down
4 changes: 2 additions & 2 deletions Sources/Workspace/DefaultPluginScriptRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable {

// Set up a pipe for receiving messages from the plugin on its stdout.
let stdoutPipe = Pipe()
let stdoutLock = Lock()
let stdoutLock = NSLock()
stdoutPipe.fileHandleForReading.readabilityHandler = { fileHandle in
// Receive the next message and pass it on to the delegate.
stdoutLock.withLock {
Expand Down Expand Up @@ -448,7 +448,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable {

// Set up a pipe for receiving free-form text output from the plugin on its stderr.
let stderrPipe = Pipe()
let stderrLock = Lock()
let stderrLock = NSLock()
var stderrData = Data()
let stderrHandler = { (data: Data) in
// Pass on any available data to the delegate.
Expand Down
3 changes: 2 additions & 1 deletion Sources/Workspace/ResolvedFileWatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

import class Foundation.NSLock
import PackageModel
import PackageGraph
import TSCBasic
Expand All @@ -22,7 +23,7 @@ import class TSCUtility.FSWatch
final class ResolvedFileWatcher {
private var fswatch: FSWatch!
private var existingValue: ByteString?
private let valueLock: Lock = Lock()
private let valueLock = NSLock()
private let resolvedFile: AbsolutePath

public func updateValue() {
Expand Down
3 changes: 2 additions & 1 deletion Sources/Workspace/SourceControlPackageContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import Basics
import Dispatch
import class Foundation.NSLock
import PackageFingerprint
import PackageGraph
import PackageLoading
Expand Down Expand Up @@ -63,7 +64,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri

/// The cached dependency information.
private var dependenciesCache = [String: [ProductFilter: (Manifest, [Constraint])]] ()
private var dependenciesCacheLock = Lock()
private var dependenciesCacheLock = NSLock()

private var knownVersionsCache = ThreadSafeBox<[Version: String]>()
private var manifestsCache = ThreadSafeKeyValueStore<String, Manifest>()
Expand Down
4 changes: 2 additions & 2 deletions Sources/Workspace/Workspace+Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ extension Workspace.Configuration {
private let fileSystem: FileSystem

private var _mirrors: DependencyMirrors
private let lock = Lock()
private let lock = NSLock()

/// The mirrors in this configuration
public var mirrors: DependencyMirrors {
Expand Down Expand Up @@ -565,7 +565,7 @@ extension Workspace.Configuration {
private let fileSystem: FileSystem

private var _configuration = RegistryConfiguration()
private let lock = Lock()
private let lock = NSLock()

/// The registry configuration
public var configuration: RegistryConfiguration {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Workspace/Workspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ extension Workspace {
observabilityScope: ObservabilityScope,
completion: @escaping(Result<[AbsolutePath: Manifest], Error>) -> Void
) {
let lock = Lock()
let lock = NSLock()
let sync = DispatchGroup()
var rootManifests = [AbsolutePath: Manifest]()
Set(packages).forEach { package in
Expand Down
2 changes: 1 addition & 1 deletion Tests/BasicsTests/CancellatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ fileprivate struct Worker {
class ProcessStartedSemaphore {
let term: String
let underlying = DispatchSemaphore(value: 0)
let lock = Lock()
let lock = NSLock()
var trapped = false
var output = ""

Expand Down
7 changes: 3 additions & 4 deletions Tests/BasicsTests/ConcurrencyHelpersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//

@testable import Basics
import TSCBasic
import TSCTestSupport
import XCTest

Expand All @@ -23,7 +22,7 @@ final class ConcurrencyHelpersTest: XCTestCase {
let sync = DispatchGroup()

var expected = [Int: Int]()
let lock = Lock()
let lock = NSLock()

let cache = ThreadSafeKeyValueStore<Int, Int>()
for index in 0 ..< 1000 {
Expand Down Expand Up @@ -58,7 +57,7 @@ final class ConcurrencyHelpersTest: XCTestCase {
let sync = DispatchGroup()

var expected = [Int]()
let lock = Lock()
let lock = NSLock()

let cache = ThreadSafeArrayStore<Int>()
for _ in 0 ..< 1000 {
Expand Down Expand Up @@ -88,7 +87,7 @@ final class ConcurrencyHelpersTest: XCTestCase {
let sync = DispatchGroup()

var winner: Int?
let lock = Lock()
let lock = NSLock()

let serial = DispatchQueue(label: "testThreadSafeBoxSerial")

Expand Down
Loading