Skip to content
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

Add ConnectionIDGenerator and NoOpKeepAliveBehavior #418

Merged
merged 2 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 15 additions & 0 deletions Sources/ConnectionPoolModule/ConnectionIDGenerator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Atomics

public struct ConnectionIDGenerator: ConnectionIDGeneratorProtocol {
static let globalGenerator = ConnectionIDGenerator()

private let atomic: ManagedAtomic<Int>

public init() {
self.atomic = .init(0)
}

public func next() -> Int {
return self.atomic.loadThenWrappingIncrement(ordering: .relaxed)
}
}
8 changes: 8 additions & 0 deletions Sources/ConnectionPoolModule/NoKeepAliveBehavior.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
public struct NoOpKeepAliveBehavior<Connection: PooledConnection>: ConnectionKeepAliveBehavior {
public var keepAliveFrequency: Duration? { nil }

public func runKeepAlive(for connection: Connection) async throws {}

public init(connectionType: Connection.Type) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import _ConnectionPoolModule
import XCTest

final class ConnectionIDGeneratorTests: XCTestCase {
func testGenerateConnectionIDs() async {
let idGenerator = ConnectionIDGenerator()

XCTAssertEqual(idGenerator.next(), 0)
XCTAssertEqual(idGenerator.next(), 1)
XCTAssertEqual(idGenerator.next(), 2)

await withTaskGroup(of: Void.self) { taskGroup in
for _ in 0..<1000 {
taskGroup.addTask {
_ = idGenerator.next()
}
}
}

XCTAssertEqual(idGenerator.next(), 1003)
}
}
74 changes: 74 additions & 0 deletions Tests/ConnectionPoolModuleTests/Mocks/MockConnection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import DequeModule
@testable import _ConnectionPoolModule

// Sendability enforced through the lock
final class MockConnection: PooledConnection, @unchecked Sendable {
typealias ID = Int

let id: ID

private enum State {
case running([@Sendable ((any Error)?) -> ()])
case closing([@Sendable ((any Error)?) -> ()])
case closed
}

private let lock = NIOLock()
private var _state = State.running([])

init(id: Int) {
self.id = id
}

func onClose(_ closure: @escaping @Sendable ((any Error)?) -> ()) {
let enqueued = self.lock.withLock { () -> Bool in
switch self._state {
case .closed:
return false

case .running(var callbacks):
callbacks.append(closure)
self._state = .running(callbacks)
return true

case .closing(var callbacks):
callbacks.append(closure)
self._state = .closing(callbacks)
return true
}
}

if !enqueued {
closure(nil)
}
}

func close() {
self.lock.withLock {
switch self._state {
case .running(let callbacks):
self._state = .closing(callbacks)

case .closing, .closed:
break
}
}
}

func closeIfClosing() {
let callbacks = self.lock.withLock { () -> [@Sendable ((any Error)?) -> ()] in
switch self._state {
case .running, .closed:
return []

case .closing(let callbacks):
self._state = .closed
return callbacks
}
}

for callback in callbacks {
callback(nil)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import _ConnectionPoolModule
import XCTest

final class NoKeepAliveBehaviorTests: XCTestCase {
func testNoKeepAlive() {
let keepAliveBehavior = NoOpKeepAliveBehavior(connectionType: MockConnection.self)
XCTAssertNil(keepAliveBehavior.keepAliveFrequency)
}
}
1 change: 0 additions & 1 deletion Tests/ConnectionPoolModuleTests/gitkeep.swift

This file was deleted.