Skip to content

Commit 40b05b2

Browse files
committed
Perform internal database operations in FIFO queue
This breaks our embargo with Foundation, but our application had been suffering as a result. Signed-off-by: Stephen Celis <stephen@stephencelis.com>
1 parent db6d662 commit 40b05b2

File tree

2 files changed

+25
-15
lines changed

2 files changed

+25
-15
lines changed

SQLite Common/Database.swift

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
// THE SOFTWARE.
2222
//
2323

24+
import Foundation
25+
2426
/// A connection (handle) to a SQLite database.
2527
public final class Database {
2628

27-
private let handle: COpaquePointer = nil
29+
internal let handle: COpaquePointer = nil
2830

2931
/// Whether or not the database was opened in a read-only state.
3032
public var readonly: Bool { return sqlite3_db_readonly(handle, nil) == 1 }
@@ -46,7 +48,7 @@ public final class Database {
4648
try(sqlite3_open_v2(path ?? "", &handle, flags, nil))
4749
}
4850

49-
deinit { sqlite3_close(handle) } // sqlite3_close_v2 in Yosemite/iOS 8?
51+
deinit { try(sqlite3_close(handle)) } // sqlite3_close_v2 in Yosemite/iOS 8?
5052

5153
// MARK: -
5254

@@ -86,10 +88,7 @@ public final class Database {
8688
/// :returns: A prepared statement.
8789
public func prepare(statement: String, _ bindings: Binding?...) -> Statement {
8890
if !bindings.isEmpty { return prepare(statement, bindings) }
89-
90-
var statementHandle: COpaquePointer = nil
91-
try(sqlite3_prepare_v2(handle, statement, -1, &statementHandle, nil))
92-
return Statement(statementHandle)
91+
return Statement(self, statement)
9392
}
9493

9594
/// Prepares a single SQL statement and binds parameters to it.
@@ -332,10 +331,16 @@ public final class Database {
332331
return String.fromCString(sqlite3_errmsg(handle))!
333332
}
334333

335-
private func try(block: @autoclosure () -> Int32) {
336-
if block() != SQLITE_OK { assertionFailure("\(lastError)") }
334+
internal func try(block: @autoclosure () -> Int32) {
335+
perform { if block() != SQLITE_OK { assertionFailure("\(self.lastError)") } }
337336
}
338337

338+
// MARK: - Threading
339+
340+
private let queue = dispatch_queue_create("SQLite.Database", DISPATCH_QUEUE_SERIAL)
341+
342+
internal func perform(block: () -> ()) { dispatch_sync(queue, block) }
343+
339344
}
340345

341346
extension Database: DebugPrintable {

SQLite Common/Statement.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ private let SQLITE_TRANSIENT = sqlite3_destructor_type(COpaquePointer(bitPattern
2727
/// A single SQL statement.
2828
public final class Statement {
2929

30-
private let handle: COpaquePointer
30+
private let handle: COpaquePointer = nil
3131

32-
private var database: COpaquePointer { return sqlite3_db_handle(handle) }
32+
private var database: Database
3333

34-
internal init(_ handle: COpaquePointer) { self.handle = handle }
34+
internal init(_ database: Database, _ SQL: String) {
35+
self.database = database
36+
database.try(sqlite3_prepare_v2(database.handle, SQL, -1, &handle, nil))
37+
}
3538

3639
deinit { sqlite3_finalize(handle) }
3740

@@ -171,10 +174,12 @@ public final class Statement {
171174

172175
private func try(block: @autoclosure () -> Int32) {
173176
if failed { return }
174-
status = block()
175-
if failed {
176-
reason = String.fromCString(sqlite3_errmsg(database))
177-
assert(status == SQLITE_CONSTRAINT, "\(reason!)")
177+
database.perform {
178+
self.status = block()
179+
if self.failed {
180+
self.reason = String.fromCString(sqlite3_errmsg(self.database.handle))
181+
assert(self.status == SQLITE_CONSTRAINT, "\(self.reason!)")
182+
}
178183
}
179184
}
180185

0 commit comments

Comments
 (0)