Skip to content

Commit 21473f5

Browse files
authored
Remove warn-concurrency warnings (vapor#408)
1 parent 2905779 commit 21473f5

21 files changed

+164
-94
lines changed

Sources/PostgresNIO/Connection/PostgresConnection+Configuration.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import NIOSSL
44

55
extension PostgresConnection {
66
/// A configuration object for a connection
7-
public struct Configuration {
8-
7+
public struct Configuration: Sendable {
8+
99
// MARK: - TLS
1010

1111
/// The possible modes of operation for TLS encapsulation of a connection.
12-
public struct TLS {
12+
public struct TLS: Sendable {
1313
// MARK: Initializers
1414

1515
/// Do not try to create a TLS connection to the server.
@@ -63,7 +63,7 @@ extension PostgresConnection {
6363
// MARK: - Connection options
6464

6565
/// Describes options affecting how the underlying connection is made.
66-
public struct Options {
66+
public struct Options: Sendable {
6767
/// A timeout for connection attempts. Defaults to ten seconds.
6868
///
6969
/// Ignored when using a preexisting communcation channel. (See
@@ -219,7 +219,7 @@ extension PostgresConnection {
219219
/// the deprecated configuration.
220220
///
221221
/// TODO: Drop with next major release
222-
struct InternalConfiguration {
222+
struct InternalConfiguration: Sendable {
223223
enum Connection {
224224
case unresolvedTCP(host: String, port: Int)
225225
case unresolvedUDS(path: String)

Sources/PostgresNIO/Connection/PostgresConnection.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ public final class PostgresConnection: @unchecked Sendable {
144144
on eventLoop: EventLoop
145145
) -> EventLoopFuture<PostgresConnection> {
146146

147-
var logger = logger
148-
logger[postgresMetadataKey: .connectionID] = "\(connectionID)"
147+
var mlogger = logger
148+
mlogger[postgresMetadataKey: .connectionID] = "\(connectionID)"
149+
let logger = mlogger
149150

150151
// Here we dispatch to the `eventLoop` first before we setup the EventLoopFuture chain, to
151152
// ensure all `flatMap`s are executed on the EventLoop (this means the enqueuing of the
@@ -567,12 +568,13 @@ extension PostgresConnection {
567568
/// - line: The line, the query was started in. Used for better error reporting.
568569
/// - onRow: A closure that is invoked for every row.
569570
/// - Returns: An EventLoopFuture, that allows access to the future ``PostgresQueryMetadata``.
571+
@preconcurrency
570572
public func query(
571573
_ query: PostgresQuery,
572574
logger: Logger,
573575
file: String = #fileID,
574576
line: Int = #line,
575-
_ onRow: @escaping (PostgresRow) throws -> ()
577+
_ onRow: @escaping @Sendable (PostgresRow) throws -> ()
576578
) -> EventLoopFuture<PostgresQueryMetadata> {
577579
self.queryStream(query, logger: logger).flatMap { rowStream in
578580
rowStream.onRow(onRow).flatMapThrowing { () -> PostgresQueryMetadata in
@@ -638,18 +640,19 @@ extension PostgresConnection: PostgresDatabase {
638640
}
639641
}
640642

643+
@preconcurrency
641644
public func withConnection<T>(_ closure: (PostgresConnection) -> EventLoopFuture<T>) -> EventLoopFuture<T> {
642645
closure(self)
643646
}
644647
}
645648

646649
internal enum PostgresCommands: PostgresRequest {
647650
case query(PostgresQuery,
648-
onMetadata: (PostgresQueryMetadata) -> () = { _ in },
649-
onRow: (PostgresRow) throws -> ())
650-
case queryAll(PostgresQuery, onResult: (PostgresQueryResult) -> ())
651+
onMetadata: @Sendable (PostgresQueryMetadata) -> () = { _ in },
652+
onRow: @Sendable (PostgresRow) throws -> ())
653+
case queryAll(PostgresQuery, onResult: @Sendable (PostgresQueryResult) -> ())
651654
case prepareQuery(request: PrepareQueryRequest)
652-
case executePreparedStatement(query: PreparedQuery, binds: [PostgresData], onRow: (PostgresRow) throws -> ())
655+
case executePreparedStatement(query: PreparedQuery, binds: [PostgresData], onRow: @Sendable (PostgresRow) throws -> ())
653656

654657
func respond(to message: PostgresMessage) throws -> [PostgresMessage]? {
655658
fatalError("This function must not be called")

Sources/PostgresNIO/Connection/PostgresDatabase+PreparedQuery.swift

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import NIOCore
2+
import NIOConcurrencyHelpers
23
import struct Foundation.UUID
34

45
extension PostgresDatabase {
@@ -14,7 +15,8 @@ extension PostgresDatabase {
1415
}
1516
}
1617

17-
public func prepare(query: String, handler: @escaping (PreparedQuery) -> EventLoopFuture<[[PostgresRow]]>) -> EventLoopFuture<[[PostgresRow]]> {
18+
@preconcurrency
19+
public func prepare(query: String, handler: @Sendable @escaping (PreparedQuery) -> EventLoopFuture<[[PostgresRow]]>) -> EventLoopFuture<[[PostgresRow]]> {
1820
prepare(query: query)
1921
.flatMap { preparedQuery in
2022
handler(preparedQuery)
@@ -26,7 +28,7 @@ extension PostgresDatabase {
2628
}
2729

2830

29-
public struct PreparedQuery {
31+
public struct PreparedQuery: Sendable {
3032
let underlying: PSQLPreparedStatement
3133
let database: PostgresDatabase
3234

@@ -36,11 +38,16 @@ public struct PreparedQuery {
3638
}
3739

3840
public func execute(_ binds: [PostgresData] = []) -> EventLoopFuture<[PostgresRow]> {
39-
var rows: [PostgresRow] = []
40-
return self.execute(binds) { rows.append($0) }.map { rows }
41+
let rowsBoxed = NIOLockedValueBox([PostgresRow]())
42+
return self.execute(binds) { row in
43+
rowsBoxed.withLockedValue {
44+
$0.append(row)
45+
}
46+
}.map { rowsBoxed.withLockedValue { $0 } }
4147
}
4248

43-
public func execute(_ binds: [PostgresData] = [], _ onRow: @escaping (PostgresRow) throws -> ()) -> EventLoopFuture<Void> {
49+
@preconcurrency
50+
public func execute(_ binds: [PostgresData] = [], _ onRow: @Sendable @escaping (PostgresRow) throws -> ()) -> EventLoopFuture<Void> {
4451
let command = PostgresCommands.executePreparedStatement(query: self, binds: binds, onRow: onRow)
4552
return self.database.send(command, logger: self.database.logger)
4653
}
@@ -50,15 +57,23 @@ public struct PreparedQuery {
5057
}
5158
}
5259

53-
final class PrepareQueryRequest {
60+
final class PrepareQueryRequest: Sendable {
5461
let query: String
5562
let name: String
56-
var prepared: PreparedQuery? = nil
57-
58-
63+
var prepared: PreparedQuery? {
64+
get {
65+
self._prepared.withLockedValue { $0 }
66+
}
67+
set {
68+
self._prepared.withLockedValue {
69+
$0 = newValue
70+
}
71+
}
72+
}
73+
let _prepared: NIOLockedValueBox<PreparedQuery?> = .init(nil)
74+
5975
init(_ query: String, as name: String) {
6076
self.query = query
6177
self.name = name
6278
}
63-
6479
}

Sources/PostgresNIO/Message/PostgresMessage+Error.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import NIOCore
22

33
extension PostgresMessage {
44
/// First message sent from the frontend during startup.
5-
public struct Error: CustomStringConvertible {
6-
public enum Field: UInt8, Hashable {
5+
public struct Error: CustomStringConvertible, Sendable {
6+
public enum Field: UInt8, Hashable, Sendable {
77
/// Severity: the field contents are ERROR, FATAL, or PANIC (in an error message),
88
/// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
99
//// localized translation of one of these. Always present.

Sources/PostgresNIO/New/NotificationListener.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ final class NotificationListener: @unchecked Sendable {
4444

4545
func startListeningSucceeded(handler: PostgresChannelHandler) {
4646
self.eventLoop.preconditionInEventLoop()
47+
let handlerLoopBound = NIOLoopBound(handler, eventLoop: self.eventLoop)
4748

4849
switch self.state {
4950
case .streamInitialized(let checkedContinuation):
@@ -55,7 +56,7 @@ final class NotificationListener: @unchecked Sendable {
5556
switch reason {
5657
case .cancelled:
5758
eventLoop.execute {
58-
handler.cancelNotificationListener(channel: channel, id: listenerID)
59+
handlerLoopBound.value.cancelNotificationListener(channel: channel, id: listenerID)
5960
}
6061

6162
case .finished:

Sources/PostgresNIO/New/PSQLError.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import NIOCore
22

33
/// An error that is thrown from the PostgresClient.
4-
public struct PSQLError: Error {
4+
/// Sendability enforced through Copy on Write semantics
5+
public struct PSQLError: Error, @unchecked Sendable {
56

67
public struct Code: Sendable, Hashable, CustomStringConvertible {
78
enum Base: Sendable, Hashable {

Sources/PostgresNIO/New/PSQLRowStream.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,8 @@ final class PSQLRowStream: @unchecked Sendable {
9696
let yieldResult = source.yield(contentsOf: bufferedRows)
9797
self.downstreamState = .asyncSequence(source, dataSource)
9898

99-
self.eventLoop.execute {
100-
self.executeActionBasedOnYieldResult(yieldResult, source: dataSource)
101-
}
102-
99+
self.executeActionBasedOnYieldResult(yieldResult, source: dataSource)
100+
103101
case .finished(let buffer, let commandTag):
104102
_ = source.yield(contentsOf: buffer)
105103
source.finish()
@@ -206,7 +204,7 @@ final class PSQLRowStream: @unchecked Sendable {
206204

207205
// MARK: Consume on EventLoop
208206

209-
func onRow(_ onRow: @escaping (PostgresRow) throws -> ()) -> EventLoopFuture<Void> {
207+
func onRow(_ onRow: @Sendable @escaping (PostgresRow) throws -> ()) -> EventLoopFuture<Void> {
210208
if self.eventLoop.inEventLoop {
211209
return self.onRow0(onRow)
212210
} else {

Sources/PostgresNIO/New/PSQLTask.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ final class ExtendedQueryContext {
7070
}
7171
}
7272

73-
final class PreparedStatementContext{
73+
final class PreparedStatementContext: Sendable {
7474
let name: String
7575
let sql: String
7676
let bindings: PostgresBindings

Sources/PostgresNIO/New/PostgresChannelHandler.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -597,8 +597,10 @@ final class PostgresChannelHandler: ChannelDuplexHandler {
597597
logger: self.logger,
598598
promise: promise
599599
)
600+
let loopBound = NIOLoopBound((self, context), eventLoop: self.eventLoop)
600601
promise.futureResult.whenComplete { result in
601-
self.startListenCompleted(result, for: channel, context: context)
602+
let (selfTransferred, context) = loopBound.value
603+
selfTransferred.startListenCompleted(result, for: channel, context: context)
602604
}
603605

604606
return .extendedQuery(query)
@@ -643,8 +645,10 @@ final class PostgresChannelHandler: ChannelDuplexHandler {
643645
logger: self.logger,
644646
promise: promise
645647
)
648+
let loopBound = NIOLoopBound((self, context), eventLoop: self.eventLoop)
646649
promise.futureResult.whenComplete { result in
647-
self.stopListenCompleted(result, for: channel, context: context)
650+
let (selfTransferred, context) = loopBound.value
651+
selfTransferred.stopListenCompleted(result, for: channel, context: context)
648652
}
649653

650654
return .extendedQuery(query)
@@ -693,10 +697,12 @@ final class PostgresChannelHandler: ChannelDuplexHandler {
693697
context: ChannelHandlerContext
694698
) -> PSQLTask {
695699
let promise = self.eventLoop.makePromise(of: RowDescription?.self)
700+
let loopBound = NIOLoopBound((self, context), eventLoop: self.eventLoop)
696701
promise.futureResult.whenComplete { result in
702+
let (selfTransferred, context) = loopBound.value
697703
switch result {
698704
case .success(let rowDescription):
699-
self.prepareStatementComplete(
705+
selfTransferred.prepareStatementComplete(
700706
name: preparedStatement.name,
701707
rowDescription: rowDescription,
702708
context: context
@@ -708,7 +714,7 @@ final class PostgresChannelHandler: ChannelDuplexHandler {
708714
} else {
709715
psqlError = .connectionError(underlying: error)
710716
}
711-
self.prepareStatementFailed(
717+
selfTransferred.prepareStatementFailed(
712718
name: preparedStatement.name,
713719
error: psqlError,
714720
context: context

Sources/PostgresNIO/New/PostgresCodable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ extension PostgresEncodingContext where JSONEncoder == Foundation.JSONEncoder {
188188

189189
/// A context that is passed to Swift objects that are decoded from the Postgres wire format. Used
190190
/// to pass further information to the decoding method.
191-
public struct PostgresDecodingContext<JSONDecoder: PostgresJSONDecoder> {
191+
public struct PostgresDecodingContext<JSONDecoder: PostgresJSONDecoder>: Sendable {
192192
/// A ``PostgresJSONDecoder`` used to decode the object from json.
193193
public var jsonDecoder: JSONDecoder
194194

Sources/PostgresNIO/PostgresDatabase+Query.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
11
import NIOCore
22
import Logging
3+
import NIOConcurrencyHelpers
34

45
extension PostgresDatabase {
56
public func query(
67
_ string: String,
78
_ binds: [PostgresData] = []
89
) -> EventLoopFuture<PostgresQueryResult> {
9-
var rows: [PostgresRow] = []
10-
var metadata: PostgresQueryMetadata?
11-
return self.query(string, binds, onMetadata: {
12-
metadata = $0
13-
}) {
14-
rows.append($0)
10+
let box = NIOLockedValueBox((metadata: PostgresQueryMetadata?.none, rows: [PostgresRow]()))
11+
12+
return self.query(string, binds, onMetadata: { metadata in
13+
box.withLockedValue {
14+
$0.metadata = metadata
15+
}
16+
}) { row in
17+
box.withLockedValue {
18+
$0.rows.append(row)
19+
}
1520
}.map {
16-
.init(metadata: metadata!, rows: rows)
21+
box.withLockedValue {
22+
PostgresQueryResult(metadata: $0.metadata!, rows: $0.rows)
23+
}
1724
}
1825
}
1926

27+
@preconcurrency
2028
public func query(
2129
_ string: String,
2230
_ binds: [PostgresData] = [],
23-
onMetadata: @escaping (PostgresQueryMetadata) -> () = { _ in },
24-
onRow: @escaping (PostgresRow) throws -> ()
31+
onMetadata: @Sendable @escaping (PostgresQueryMetadata) -> () = { _ in },
32+
onRow: @Sendable @escaping (PostgresRow) throws -> ()
2533
) -> EventLoopFuture<Void> {
2634
var bindings = PostgresBindings(capacity: binds.count)
2735
binds.forEach { bindings.append($0) }
@@ -58,7 +66,7 @@ extension PostgresQueryResult: Collection {
5866
}
5967
}
6068

61-
public struct PostgresQueryMetadata {
69+
public struct PostgresQueryMetadata: Sendable {
6270
public let command: String
6371
public var oid: Int?
6472
public var rows: Int?
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import NIOCore
2+
import NIOConcurrencyHelpers
23
import Logging
34

45
extension PostgresDatabase {
56
public func simpleQuery(_ string: String) -> EventLoopFuture<[PostgresRow]> {
6-
var rows: [PostgresRow] = []
7-
return simpleQuery(string) { rows.append($0) }.map { rows }
7+
let rowsBoxed = NIOLockedValueBox([PostgresRow]())
8+
return self.simpleQuery(string) { row in
9+
rowsBoxed.withLockedValue {
10+
$0.append(row)
11+
}
12+
}.map { rowsBoxed.withLockedValue { $0 } }
813
}
914

10-
public func simpleQuery(_ string: String, _ onRow: @escaping (PostgresRow) throws -> ()) -> EventLoopFuture<Void> {
15+
@preconcurrency
16+
public func simpleQuery(_ string: String, _ onRow: @Sendable @escaping (PostgresRow) throws -> ()) -> EventLoopFuture<Void> {
1117
self.query(string, onRow: onRow)
1218
}
1319
}

Sources/PostgresNIO/PostgresDatabase.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import NIOCore
22
import Logging
33

4-
public protocol PostgresDatabase {
4+
@preconcurrency
5+
public protocol PostgresDatabase: Sendable {
56
var logger: Logger { get }
67
var eventLoop: EventLoop { get }
78
func send(
89
_ request: PostgresRequest,
910
logger: Logger
1011
) -> EventLoopFuture<Void>
11-
12+
1213
func withConnection<T>(_ closure: @escaping (PostgresConnection) -> EventLoopFuture<T>) -> EventLoopFuture<T>
1314
}
1415

0 commit comments

Comments
 (0)