Skip to content

Commit f19180d

Browse files
authored
Reduce platform requirements (#102)
* Reduce platform requirements * Add @available(valkeySwift 1.0, *) for ValkeyClient.pipeline
1 parent 5cd86f6 commit f19180d

22 files changed

+239
-111
lines changed

Benchmarks/ValkeyBenchmarks/ValkeyBenchmarks.swift

Lines changed: 87 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -35,109 +35,112 @@ let benchmarks: @Sendable () -> Void = {
3535
.throughput,
3636
]
3737

38-
var server: Channel?
39-
Benchmark("GET benchmark", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
40-
let port = server!.localAddress!.port!
41-
let logger = Logger(label: "test")
42-
let client = ValkeyClient(.hostname("127.0.0.1", port: port), logger: logger)
43-
44-
try await withThrowingTaskGroup(of: Void.self) { group in
45-
group.addTask {
46-
await client.run()
47-
}
48-
await Task.yield()
49-
try await client.withConnection { connection in
50-
benchmark.startMeasurement()
38+
var server: (any Channel)?
39+
40+
if #available(valkeySwift 1.0, *) {
41+
Benchmark("GET benchmark", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
42+
let port = server!.localAddress!.port!
43+
let logger = Logger(label: "test")
44+
let client = ValkeyClient(.hostname("127.0.0.1", port: port), logger: logger)
5145

52-
for _ in benchmark.scaledIterations {
53-
let foo = try await connection.get(key: "foo")?.decode(as: String.self)
54-
precondition(foo == "Bar")
46+
try await withThrowingTaskGroup(of: Void.self) { group in
47+
group.addTask {
48+
await client.run()
5549
}
50+
await Task.yield()
51+
try await client.withConnection { connection in
52+
benchmark.startMeasurement()
5653

57-
benchmark.stopMeasurement()
58-
}
59-
group.cancelAll()
60-
}
61-
} setup: {
62-
struct GetHandler: BenchmarkCommandHandler {
63-
static let expectedCommand = RESPToken.Value.bulkString(ByteBuffer(string: "GET"))
64-
static let response = ByteBuffer(string: "$3\r\nBar\r\n")
65-
func handle(command: RESPToken.Value, parameters: RESPToken.Array.Iterator, write: (ByteBuffer) -> Void) {
66-
switch command {
67-
case Self.expectedCommand:
68-
write(Self.response)
69-
default:
70-
fatalError()
54+
for _ in benchmark.scaledIterations {
55+
let foo = try await connection.get(key: "foo")?.decode(as: String.self)
56+
precondition(foo == "Bar")
57+
}
58+
59+
benchmark.stopMeasurement()
7160
}
61+
group.cancelAll()
7262
}
73-
}
74-
server = try await ServerBootstrap(group: NIOSingletons.posixEventLoopGroup)
75-
.childChannelInitializer { channel in
76-
do {
77-
try channel.pipeline.syncOperations.addHandler(
78-
ValkeyServerChannelHandler(commandHandler: GetHandler())
79-
)
80-
return channel.eventLoop.makeSucceededVoidFuture()
81-
} catch {
82-
return channel.eventLoop.makeFailedFuture(error)
63+
} setup: {
64+
struct GetHandler: BenchmarkCommandHandler {
65+
static let expectedCommand = RESPToken.Value.bulkString(ByteBuffer(string: "GET"))
66+
static let response = ByteBuffer(string: "$3\r\nBar\r\n")
67+
func handle(command: RESPToken.Value, parameters: RESPToken.Array.Iterator, write: (ByteBuffer) -> Void) {
68+
switch command {
69+
case Self.expectedCommand:
70+
write(Self.response)
71+
default:
72+
fatalError()
73+
}
8374
}
8475
}
85-
.bind(host: "127.0.0.1", port: 0)
86-
.get()
87-
} teardown: {
88-
try await server?.close().get()
89-
}
76+
server = try await ServerBootstrap(group: NIOSingletons.posixEventLoopGroup)
77+
.childChannelInitializer { channel in
78+
do {
79+
try channel.pipeline.syncOperations.addHandler(
80+
ValkeyServerChannelHandler(commandHandler: GetHandler())
81+
)
82+
return channel.eventLoop.makeSucceededVoidFuture()
83+
} catch {
84+
return channel.eventLoop.makeFailedFuture(error)
85+
}
86+
}
87+
.bind(host: "127.0.0.1", port: 0)
88+
.get()
89+
} teardown: {
90+
try await server?.close().get()
91+
}
9092

91-
Benchmark("ValkeyCommandEncoder – Simple GET", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
92-
let command = GET(key: "foo")
93-
benchmark.startMeasurement()
93+
Benchmark("ValkeyCommandEncoder – Simple GET", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
94+
let command = GET(key: "foo")
95+
benchmark.startMeasurement()
9496

95-
var encoder = ValkeyCommandEncoder()
96-
for _ in benchmark.scaledIterations {
97-
encoder.reset()
98-
command.encode(into: &encoder)
97+
var encoder = ValkeyCommandEncoder()
98+
for _ in benchmark.scaledIterations {
99+
encoder.reset()
100+
command.encode(into: &encoder)
101+
}
102+
103+
benchmark.stopMeasurement()
99104
}
100105

101-
benchmark.stopMeasurement()
102-
}
106+
Benchmark("ValkeyCommandEncoder – Simple MGET 15 keys", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
107+
let keys = (0..<15).map { ValkeyKey(rawValue: "foo-\($0)") }
108+
let command = MGET(key: keys)
109+
benchmark.startMeasurement()
103110

104-
Benchmark("ValkeyCommandEncoder – Simple MGET 15 keys", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
105-
let keys = (0..<15).map { ValkeyKey(rawValue: "foo-\($0)") }
106-
let command = MGET(key: keys)
107-
benchmark.startMeasurement()
111+
var encoder = ValkeyCommandEncoder()
112+
for _ in benchmark.scaledIterations {
113+
encoder.reset()
114+
command.encode(into: &encoder)
115+
}
108116

109-
var encoder = ValkeyCommandEncoder()
110-
for _ in benchmark.scaledIterations {
111-
encoder.reset()
112-
command.encode(into: &encoder)
117+
benchmark.stopMeasurement()
113118
}
114119

115-
benchmark.stopMeasurement()
116-
}
120+
Benchmark("ValkeyCommandEncoder – Command with 7 words", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
121+
let string = "string"
122+
let optionalString: String? = "optionalString"
123+
let array = ["array", "of", "strings"]
124+
let number = 456
125+
let token = RESPPureToken("TOKEN", true)
126+
benchmark.startMeasurement()
127+
128+
var encoder = ValkeyCommandEncoder()
129+
for _ in benchmark.scaledIterations {
130+
encoder.reset()
131+
encoder.encodeArray(string, optionalString, array, number, token)
132+
}
117133

118-
Benchmark("ValkeyCommandEncoder – Command with 7 words", configuration: .init(metrics: defaultMetrics, scalingFactor: .kilo)) { benchmark in
119-
let string = "string"
120-
let optionalString: String? = "optionalString"
121-
let array = ["array", "of", "strings"]
122-
let number = 456
123-
let token = RESPPureToken("TOKEN", true)
124-
benchmark.startMeasurement()
125-
126-
var encoder = ValkeyCommandEncoder()
127-
for _ in benchmark.scaledIterations {
128-
encoder.reset()
129-
encoder.encodeArray(string, optionalString, array, number, token)
134+
benchmark.stopMeasurement()
130135
}
131136

132-
benchmark.stopMeasurement()
133-
}
134-
135-
Benchmark("HashSlot – {user}.whatever", configuration: .init(metrics: defaultMetrics, scalingFactor: .mega)) { benchmark in
136-
let key = "{user}.whatever"
137+
Benchmark("HashSlot – {user}.whatever", configuration: .init(metrics: defaultMetrics, scalingFactor: .mega)) { benchmark in
138+
let key = "{user}.whatever"
137139

138-
benchmark.startMeasurement()
139-
for _ in benchmark.scaledIterations {
140-
blackHole(HashSlot(key: key))
140+
benchmark.startMeasurement()
141+
for _ in benchmark.scaledIterations {
142+
blackHole(HashSlot(key: key))
143+
}
141144
}
142145
}
143146
}

Package.swift

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33

44
import PackageDescription
55

6+
let defaultSwiftSettings: [SwiftSetting] =
7+
[
8+
.swiftLanguageMode(.v6),
9+
.enableExperimentalFeature("AvailabilityMacro=valkeySwift 1.0:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0"),
10+
]
11+
612
let package = Package(
713
name: "valkey-swift",
8-
platforms: [.macOS(.v15)],
14+
platforms: [.macOS(.v13)],
915
products: [
1016
.library(name: "Valkey", targets: ["Valkey"]),
1117
.library(name: "ValkeyBloom", targets: ["ValkeyBloom"]),
@@ -24,7 +30,7 @@ let package = Package(
2430
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.23.0"),
2531
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.8.0"),
2632

27-
.package(url: "https://github.com/ordo-one/package-benchmark", from: "1.29.2"),
33+
.package(url: "https://github.com/ordo-one/package-benchmark", from: "1.0.0"),
2834
],
2935
targets: [
3036
.target(
@@ -38,28 +44,33 @@ let package = Package(
3844
.product(name: "NIOSSL", package: "swift-nio-ssl"),
3945
.product(name: "NIOTransportServices", package: "swift-nio-transport-services"),
4046
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle", condition: .when(traits: ["ServiceLifecycleSupport"])),
41-
]
47+
],
48+
swiftSettings: defaultSwiftSettings
4249
),
4350
.target(
4451
name: "ValkeyBloom",
45-
dependencies: ["Valkey"]
52+
dependencies: ["Valkey"],
53+
swiftSettings: defaultSwiftSettings
4654
),
4755
.target(
4856
name: "ValkeyJSON",
49-
dependencies: ["Valkey"]
57+
dependencies: ["Valkey"],
58+
swiftSettings: defaultSwiftSettings
5059
),
5160
.target(
5261
name: "_ConnectionPoolModule",
5362
dependencies: [
5463
.product(name: "Atomics", package: "swift-atomics"),
5564
.product(name: "DequeModule", package: "swift-collections"),
5665
],
57-
path: "Sources/ConnectionPoolModule"
66+
path: "Sources/ConnectionPoolModule",
67+
swiftSettings: defaultSwiftSettings
5868
),
5969
.executableTarget(
6070
name: "ValkeyCommandsBuilder",
6171
path: "Sources/_ValkeyCommandsBuilder",
62-
resources: [.process("Resources")]
72+
resources: [.process("Resources")],
73+
swiftSettings: defaultSwiftSettings
6374
),
6475
.executableTarget(
6576
name: "ValkeyBenchmarks",
@@ -71,6 +82,7 @@ let package = Package(
7182
.product(name: "NIOPosix", package: "swift-nio"),
7283
],
7384
path: "Benchmarks/ValkeyBenchmarks",
85+
swiftSettings: defaultSwiftSettings,
7486
plugins: [
7587
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
7688
]
@@ -79,7 +91,8 @@ let package = Package(
7991
name: "IntegrationTests",
8092
dependencies: [
8193
"Valkey"
82-
]
94+
],
95+
swiftSettings: defaultSwiftSettings
8396
),
8497
.testTarget(
8598
name: "ValkeyTests",
@@ -88,7 +101,8 @@ let package = Package(
88101
.product(name: "NIOTestUtils", package: "swift-nio"),
89102
.product(name: "Logging", package: "swift-log"),
90103
.product(name: "NIOEmbedded", package: "swift-nio"),
91-
]
104+
],
105+
swiftSettings: defaultSwiftSettings
92106
),
93107
]
94108
)

Sources/Valkey/Commands/TransactionsCommands.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public struct WATCH: ValkeyCommand {
7979
}
8080
}
8181

82+
@available(valkeySwift 1.0, *)
8283
extension ValkeyConnection {
8384
/// Discards a transaction.
8485
///

Sources/Valkey/Connection/ValkeyChannelHandler+stateMachine.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import DequeModule
1616
import NIOCore
1717

18+
@available(valkeySwift 1.0, *)
1819
extension ValkeyChannelHandler {
1920
@usableFromInline
2021
struct StateMachine<Context>: ~Copyable {

Sources/Valkey/Connection/ValkeyChannelHandler.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ enum ValkeyRequest: Sendable {
4646
case multiple(buffer: ByteBuffer, promises: [ValkeyPromise<RESPToken>], id: Int)
4747
}
4848

49+
@available(valkeySwift 1.0, *)
4950
@usableFromInline
5051
final class ValkeyChannelHandler: ChannelInboundHandler {
5152
@usableFromInline

Sources/Valkey/Connection/ValkeyConnection+ConnectionPool.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Synchronization
1717
import _ConnectionPoolModule
1818

1919
/// Extend ValkeyConnection so we can use it with the connection pool
20+
@available(valkeySwift 1.0, *)
2021
extension ValkeyConnection: PooledConnection {
2122
// connection id
2223
public typealias ID = Int
@@ -27,6 +28,7 @@ extension ValkeyConnection: PooledConnection {
2728
}
2829

2930
/// Keep alive behavior for Valkey connection
31+
@available(valkeySwift 1.0, *)
3032
struct ValkeyKeepAliveBehavior: ConnectionKeepAliveBehavior {
3133
let behavior: ValkeyClientConfiguration.KeepAliveBehavior?
3234

@@ -44,6 +46,7 @@ struct ValkeyKeepAliveBehavior: ConnectionKeepAliveBehavior {
4446
}
4547

4648
/// Connection id generator for Valkey connection pool
49+
@available(valkeySwift 1.0, *)
4750
public final class ConnectionIDGenerator: ConnectionIDGeneratorProtocol {
4851
static let globalGenerator = ConnectionIDGenerator()
4952

@@ -59,6 +62,7 @@ public final class ConnectionIDGenerator: ConnectionIDGeneratorProtocol {
5962
}
6063

6164
/// Valkey client connection pool metrics
65+
@available(valkeySwift 1.0, *)
6266
final class ValkeyClientMetrics: ConnectionPoolObservabilityDelegate {
6367
typealias ConnectionID = ValkeyConnection.ID
6468

Sources/Valkey/Connection/ValkeyConnection+transactions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import NIOCore
44

5+
@available(valkeySwift 1.0, *)
56
extension ValkeyConnection {
67

78
@inlinable

Sources/Valkey/Connection/ValkeyConnection.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import NIOTransportServices
2424
#endif
2525

2626
/// Single connection to a Valkey database
27+
@available(valkeySwift 1.0, *)
2728
public final actor ValkeyConnection: ValkeyConnectionProtocol, Sendable {
2829
nonisolated public let unownedExecutor: UnownedSerialExecutor
2930

@@ -35,15 +36,15 @@ public final actor ValkeyConnection: ValkeyConnectionProtocol, Sendable {
3536
/// Logger used by Server
3637
let logger: Logger
3738
@usableFromInline
38-
let channel: Channel
39+
let channel: any Channel
3940
@usableFromInline
4041
let channelHandler: ValkeyChannelHandler
4142
let configuration: ValkeyClientConfiguration
4243
let isClosed: Atomic<Bool>
4344

4445
/// Initialize connection
4546
private init(
46-
channel: Channel,
47+
channel: any Channel,
4748
connectionID: ID,
4849
channelHandler: ValkeyChannelHandler,
4950
configuration: ValkeyClientConfiguration,

Sources/Valkey/Subscriptions/ValkeyConnection+subscribe.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import NIOCore
1616

17+
@available(valkeySwift 1.0, *)
1718
extension ValkeyConnection {
1819
/// Subscribe to list of channels and run closure with subscription
1920
///

Sources/Valkey/Subscriptions/ValkeySubscriptions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Logging
1616
import Synchronization
1717

1818
/// Container for all subscriptions on one connection
19+
@available(valkeySwift 1.0, *)
1920
@usableFromInline
2021
struct ValkeySubscriptions {
2122
var subscriptionIDMap: [Int: SubscriptionRef]

0 commit comments

Comments
 (0)