Skip to content

Commit c776077

Browse files
authored
[Collections] Shorten hold to lock on db close (#3392)
Motivation: Sometimes package-collection CLI subcommand ends with "Error: [Failed to close database]". A new `SQLitePackageCollectionsStorage` is created then destroyed for each subcommand execution. The initialization includes populating in-memory trie using data in SQLite (`populateTargetTrie`) and may take a while to complete depending on the number and size of configured collectons. There is logic in `SQLitePackageCollectionsStorage.close` to signal `populateTargetTrie` to stop, but because it keeps holding on to `stateLock`, it prevents `populateTargetTrie` from determining if it should stop and causes the "database is locked" error. Modifications: Break down the `withStateLock` block in `close` to smaller blocks such that `retryClose` is called outside of it. This allows `populateTargetTrie` to read `state` and exit if needed.
1 parent d6ed6b6 commit c776077

File tree

1 file changed

+22
-18
lines changed

1 file changed

+22
-18
lines changed

Sources/PackageCollections/Storage/SQLitePackageCollectionsStorage.swift

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,6 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
7575
}
7676

7777
func close() throws {
78-
// Signal long-running operation (e.g., populateTargetTrie) to stop
79-
try self.withStateLock {
80-
if case .connected(let db) = self.state {
81-
self.state = .disconnecting(db)
82-
do {
83-
try db.close()
84-
} catch {
85-
do {
86-
var exponentialBackoff = ExponentialBackoff()
87-
try retryClose(db: db, exponentialBackoff: &exponentialBackoff)
88-
} catch {
89-
throw StringError("Failed to close database")
90-
}
91-
}
92-
}
93-
self.state = .disconnected
94-
}
95-
9678
func retryClose(db: SQLite, exponentialBackoff: inout ExponentialBackoff) throws {
9779
let semaphore = DispatchSemaphore(value: 0)
9880
let callback = { (result: Result<Void, Error>) in
@@ -117,6 +99,28 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
11799
return try retryClose(db: db, exponentialBackoff: &exponentialBackoff)
118100
}
119101
}
102+
103+
// Signal long-running operation (e.g., populateTargetTrie) to stop
104+
if case .connected(let db) = try self.withStateLock({ self.state }) {
105+
try self.withStateLock {
106+
self.state = .disconnecting(db)
107+
}
108+
109+
do {
110+
try db.close()
111+
} catch {
112+
do {
113+
var exponentialBackoff = ExponentialBackoff()
114+
try retryClose(db: db, exponentialBackoff: &exponentialBackoff)
115+
} catch {
116+
throw StringError("Failed to close database")
117+
}
118+
}
119+
}
120+
121+
try self.withStateLock {
122+
self.state = .disconnected
123+
}
120124
}
121125

122126
func put(collection: Model.Collection,

0 commit comments

Comments
 (0)