Skip to content

Commit 78c33bc

Browse files
committed
refactor(sidebar): simplify metadata pool and drop diagnostic logging (#139)
1 parent 4071b5f commit 78c33bc

4 files changed

Lines changed: 33 additions & 174 deletions

File tree

TablePro/Core/Services/Query/DatabaseTreeMetadataService.swift

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,7 @@ final class DatabaseTreeMetadataService {
7575
// MARK: - Loads
7676

7777
func loadDatabases(connectionId: UUID, databaseType: DatabaseType) async {
78-
guard isConnected(connectionId) else {
79-
Self.logger.debug("loadDatabases skip-not-connected connId=\(connectionId, privacy: .public)")
80-
return
81-
}
78+
guard isConnected(connectionId) else { return }
8279
switch databaseListState(for: connectionId) {
8380
case .loaded, .loading: return
8481
case .idle, .failed: break
@@ -94,20 +91,16 @@ final class DatabaseTreeMetadataService {
9491
}
9592
}
9693
databaseList[connectionId] = .loaded(list)
97-
Self.logger.debug("loadDatabases loaded connId=\(connectionId, privacy: .public) count=\(list.count, privacy: .public)")
9894
} catch is CancellationError {
99-
resetIfLoading(databaseConnectionId: connectionId)
95+
if case .loading = databaseList[connectionId] { databaseList[connectionId] = .idle }
10096
} catch {
10197
databaseList[connectionId] = .failed(error.localizedDescription)
102-
Self.logger.warning("loadDatabases failed connId=\(connectionId, privacy: .public) error=\(error.localizedDescription, privacy: .public)")
98+
Self.logger.warning("databases load failed connId=\(connectionId, privacy: .public) error=\(error.localizedDescription, privacy: .public)")
10399
}
104100
}
105101

106102
func loadSchemas(connectionId: UUID, database: String) async {
107-
guard isConnected(connectionId) else {
108-
Self.logger.debug("loadSchemas skip-not-connected db=\(database, privacy: .public)")
109-
return
110-
}
103+
guard isConnected(connectionId) else { return }
111104
let key = DatabaseKey(connectionId: connectionId, database: database)
112105
switch schemaList[key] ?? .idle {
113106
case .loaded, .loading: return
@@ -121,20 +114,16 @@ final class DatabaseTreeMetadataService {
121114
}
122115
}
123116
schemaList[key] = .loaded(list)
124-
Self.logger.debug("loadSchemas loaded db=\(database, privacy: .public) count=\(list.count, privacy: .public)")
125117
} catch is CancellationError {
126118
if case .loading = schemaList[key] { schemaList[key] = .idle }
127119
} catch {
128120
schemaList[key] = .failed(error.localizedDescription)
129-
Self.logger.warning("loadSchemas failed db=\(database, privacy: .public) error=\(error.localizedDescription, privacy: .public)")
121+
Self.logger.warning("schemas load failed db=\(database, privacy: .public) error=\(error.localizedDescription, privacy: .public)")
130122
}
131123
}
132124

133125
func loadObjects(connectionId: UUID, database: String, schema: String?) async {
134-
guard isConnected(connectionId) else {
135-
Self.logger.debug("loadObjects skip-not-connected db=\(database, privacy: .public) schema=\(schema ?? "nil", privacy: .public)")
136-
return
137-
}
126+
guard isConnected(connectionId) else { return }
138127
let key = Self.objectsKey(connectionId: connectionId, database: database, schema: schema)
139128
switch objects[key] ?? .idle {
140129
case .loaded, .loading: return
@@ -155,15 +144,12 @@ final class DatabaseTreeMetadataService {
155144
}
156145
}
157146
objects[key] = .loaded(result)
158-
Self.logger.debug(
159-
"loadObjects loaded db=\(database, privacy: .public) schema=\(schema ?? "nil", privacy: .public) tables=\(result.tables.count, privacy: .public) routines=\(result.routines.count, privacy: .public)"
160-
)
161147
} catch is CancellationError {
162148
if case .loading = objects[key] { objects[key] = .idle }
163149
} catch {
164150
objects[key] = .failed(error.localizedDescription)
165151
Self.logger.warning(
166-
"loadObjects failed db=\(database, privacy: .public) schema=\(schema ?? "nil", privacy: .public) error=\(error.localizedDescription, privacy: .public)"
152+
"objects load failed db=\(database, privacy: .public) schema=\(schema ?? "nil", privacy: .public) error=\(error.localizedDescription, privacy: .public)"
167153
)
168154
}
169155
}
@@ -193,13 +179,11 @@ final class DatabaseTreeMetadataService {
193179
// MARK: - Lifecycle
194180

195181
func handleReconnect(connectionId: UUID) async {
196-
Self.logger.debug("handleReconnect connId=\(connectionId, privacy: .public)")
197182
MetadataConnectionPool.shared.closeAll(connectionId: connectionId)
198183
await resetPending(connectionId: connectionId)
199184
}
200185

201186
func handleDisconnect(connectionId: UUID) async {
202-
Self.logger.debug("handleDisconnect connId=\(connectionId, privacy: .public)")
203187
MetadataConnectionPool.shared.closeAll(connectionId: connectionId)
204188
await databaseDedup.cancel(key: connectionId)
205189
for key in schemaList.keys where key.connectionId == connectionId {
@@ -237,10 +221,6 @@ final class DatabaseTreeMetadataService {
237221
}
238222
}
239223

240-
private func resetIfLoading(databaseConnectionId connectionId: UUID) {
241-
if case .loading = databaseList[connectionId] { databaseList[connectionId] = .idle }
242-
}
243-
244224
private func isConnected(_ connectionId: UUID) -> Bool {
245225
DatabaseManager.shared.session(for: connectionId)?.status == .connected
246226
}

TablePro/Core/Services/Query/MetadataConnectionPool.swift

Lines changed: 25 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
//
55

66
import Foundation
7-
import os
87

98
@MainActor
109
final class MetadataConnectionPool {
@@ -20,91 +19,53 @@ final class MetadataConnectionPool {
2019
var lastUsed: Date
2120
var inFlightCount: Int
2221
var closeWhenIdle: Bool
23-
var tail: Task<Void, Never>
2422

2523
init(driver: DatabaseDriver) {
2624
self.driver = driver
2725
self.lastUsed = Date()
2826
self.inFlightCount = 0
2927
self.closeWhenIdle = false
30-
self.tail = Task {}
3128
}
3229
}
3330

3431
private var entries: [Key: Entry] = [:]
3532
private var pending: [Key: Task<Void, Error>] = [:]
3633
private let maxPerConnection = 4
3734
private let connectTimeoutSeconds: UInt64 = 15
38-
private static let logger = Logger(subsystem: "com.TablePro", category: "MetadataConnectionPool")
3935

4036
private init() {}
4137

4238
func withDriver<T: Sendable>(
4339
connectionId: UUID,
4440
database: String,
45-
_ body: @Sendable @escaping (DatabaseDriver) async throws -> T
41+
_ body: @Sendable (DatabaseDriver) async throws -> T
4642
) async throws -> T {
47-
Self.logger.debug(
48-
"[metadata-pool] withDriver acquire connId=\(connectionId, privacy: .public) db=\(database, privacy: .public)"
49-
)
5043
let entry = try await acquireEntry(connectionId: connectionId, database: database)
5144
entry.inFlightCount += 1
5245
entry.lastUsed = Date()
5346
defer { releaseEntry(entry) }
54-
55-
let previous = entry.tail
56-
let driver = entry.driver
57-
let work = Task { @MainActor () async throws -> T in
58-
await previous.value
59-
return try await body(driver)
60-
}
61-
entry.tail = Task { @MainActor in _ = try? await work.value }
62-
do {
63-
let result = try await work.value
64-
Self.logger.debug(
65-
"[metadata-pool] withDriver done connId=\(connectionId, privacy: .public) db=\(database, privacy: .public)"
66-
)
67-
return result
68-
} catch {
69-
Self.logger.debug(
70-
"[metadata-pool] withDriver threw connId=\(connectionId, privacy: .public) db=\(database, privacy: .public) error=\(error.localizedDescription, privacy: .public)"
71-
)
72-
throw error
73-
}
74-
}
75-
76-
private func releaseEntry(_ entry: Entry) {
77-
entry.inFlightCount -= 1
78-
guard entry.inFlightCount == 0, entry.closeWhenIdle else { return }
79-
entry.driver.disconnect()
80-
}
81-
82-
func invalidate(connectionId: UUID, database: String) {
83-
let key = Key(connectionId: connectionId, database: database)
84-
pending[key]?.cancel()
85-
pending.removeValue(forKey: key)
86-
closeOrDeferEntry(forKey: key)
47+
return try await body(entry.driver)
8748
}
8849

8950
func closeAll(connectionId: UUID) {
90-
for key in pending.keys.filter({ $0.connectionId == connectionId }) {
51+
for key in pending.keys where key.connectionId == connectionId {
9152
pending[key]?.cancel()
9253
pending.removeValue(forKey: key)
9354
}
94-
let keys = entries.keys.filter { $0.connectionId == connectionId }
95-
for key in keys {
55+
for key in entries.keys where key.connectionId == connectionId {
9656
closeOrDeferEntry(forKey: key)
9757
}
98-
if !keys.isEmpty {
99-
Self.logger.info(
100-
"[metadata-pool] closed all connId=\(connectionId, privacy: .public) count=\(keys.count, privacy: .public)"
101-
)
58+
}
59+
60+
private func releaseEntry(_ entry: Entry) {
61+
entry.inFlightCount -= 1
62+
if entry.inFlightCount == 0, entry.closeWhenIdle {
63+
entry.driver.disconnect()
10264
}
10365
}
10466

10567
private func closeOrDeferEntry(forKey key: Key) {
106-
guard let entry = entries[key] else { return }
107-
entries.removeValue(forKey: key)
68+
guard let entry = entries.removeValue(forKey: key) else { return }
10869
if entry.inFlightCount == 0 {
10970
entry.driver.disconnect()
11071
} else {
@@ -115,21 +76,16 @@ final class MetadataConnectionPool {
11576
private func acquireEntry(connectionId: UUID, database: String) async throws -> Entry {
11677
let key = Key(connectionId: connectionId, database: database)
11778
if let entry = entries[key], entry.driver.status == .connected {
118-
Self.logger.debug("[metadata-pool] reuse connId=\(connectionId, privacy: .public) db=\(database, privacy: .public)")
11979
return entry
12080
}
12181

12282
if let inFlight = pending[key] {
123-
Self.logger.debug("[metadata-pool] await-pending connId=\(connectionId, privacy: .public) db=\(database, privacy: .public)")
12483
try await inFlight.value
12584
guard let entry = entries[key] else { throw DatabaseError.notConnected }
12685
return entry
12786
}
12887

12988
guard DatabaseManager.shared.session(for: connectionId) != nil else {
130-
Self.logger.debug(
131-
"[metadata-pool] acquire-no-session connId=\(connectionId, privacy: .public) db=\(database, privacy: .public)"
132-
)
13389
throw DatabaseError.notConnected
13490
}
13591

@@ -144,13 +100,8 @@ final class MetadataConnectionPool {
144100
entries[key] = entry
145101
}
146102
pending[key] = task
147-
do {
148-
try await task.value
149-
} catch {
150-
if pending[key] == task { pending.removeValue(forKey: key) }
151-
throw error
152-
}
153-
if pending[key] == task { pending.removeValue(forKey: key) }
103+
defer { if pending[key] == task { pending.removeValue(forKey: key) } }
104+
try await task.value
154105

155106
guard let entry = entries[key] else { throw DatabaseError.notConnected }
156107
return entry
@@ -160,12 +111,11 @@ final class MetadataConnectionPool {
160111
guard let session = DatabaseManager.shared.session(for: key.connectionId) else {
161112
throw DatabaseError.notConnected
162113
}
163-
let baseConnection = session.effectiveConnection ?? session.connection
164-
var cloned = baseConnection
165-
cloned.database = key.database
114+
var connection = session.effectiveConnection ?? session.connection
115+
connection.database = key.database
166116

167117
let driver = try await DatabaseDriverFactory.createDriver(
168-
for: cloned,
118+
for: connection,
169119
passwordOverride: session.cachedPassword,
170120
awaitPlugins: true
171121
)
@@ -175,26 +125,17 @@ final class MetadataConnectionPool {
175125
driver.disconnect()
176126
throw error
177127
}
178-
Self.logger.info(
179-
"[metadata-pool] opened connId=\(key.connectionId, privacy: .public) db=\(key.database, privacy: .public)"
180-
)
181128
return Entry(driver: driver)
182129
}
183130

184131
private func connectWithTimeout(driver: DatabaseDriver, database: String) async throws {
185132
let timeoutNanos = connectTimeoutSeconds * 1_000_000_000
186133
try await withThrowingTaskGroup(of: Void.self) { group in
187-
group.addTask {
188-
try await driver.connect()
189-
}
134+
group.addTask { try await driver.connect() }
190135
group.addTask {
191136
try await Task.sleep(nanoseconds: timeoutNanos)
192-
throw NSError(
193-
domain: "MetadataConnectionPool",
194-
code: NSURLErrorTimedOut,
195-
userInfo: [NSLocalizedDescriptionKey: String(
196-
format: String(localized: "Connecting to '%@' timed out."), database
197-
)]
137+
throw DatabaseError.connectionFailed(
138+
String(format: String(localized: "Connecting to '%@' timed out."), database)
198139
)
199140
}
200141
try await group.next()
@@ -206,12 +147,11 @@ final class MetadataConnectionPool {
206147
let live = entries.filter { $0.key.connectionId == connectionId }
207148
let pendingCount = pending.keys.filter { $0.connectionId == connectionId }.count
208149
guard live.count + pendingCount >= maxPerConnection else { return }
209-
let idle = live.filter { $0.value.inFlightCount == 0 }
210-
guard let oldest = idle.min(by: { $0.value.lastUsed < $1.value.lastUsed }) else { return }
211-
entries[oldest.key]?.driver.disconnect()
212-
entries.removeValue(forKey: oldest.key)
213-
Self.logger.info(
214-
"[metadata-pool] evicted connId=\(connectionId, privacy: .public) db=\(oldest.key.database, privacy: .public)"
215-
)
150+
let oldestIdle = live
151+
.filter { $0.value.inFlightCount == 0 }
152+
.min { $0.value.lastUsed < $1.value.lastUsed }
153+
guard let oldestIdle else { return }
154+
oldestIdle.value.driver.disconnect()
155+
entries.removeValue(forKey: oldestIdle.key)
216156
}
217157
}

TablePro/Core/Services/Query/MetadataLoadState.swift

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,6 @@ enum MetadataLoadState<Value: Sendable>: Sendable {
1515
if case .loaded(let value) = self { return value }
1616
return nil
1717
}
18-
19-
var label: String {
20-
switch self {
21-
case .idle: return "idle"
22-
case .loading: return "loading"
23-
case .loaded: return "loaded"
24-
case .failed: return "failed"
25-
}
26-
}
2718
}
2819

2920
extension MetadataLoadState: Equatable where Value: Equatable {}
30-
31-
extension SchemaState {
32-
var label: String {
33-
switch self {
34-
case .idle: return "idle"
35-
case .loading: return "loading"
36-
case .loaded(let tables): return "loaded(\(tables.count))"
37-
case .failed: return "failed"
38-
}
39-
}
40-
}
41-
42-
extension ConnectionStatus {
43-
var label: String {
44-
switch self {
45-
case .disconnected: return "disconnected"
46-
case .connecting: return "connecting"
47-
case .connected: return "connected"
48-
case .error: return "error"
49-
}
50-
}
51-
}

0 commit comments

Comments
 (0)