From 31887b39e5f749f82196f3a3ad6c563b26e7f2aa Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Mon, 6 Nov 2023 11:01:05 +0800 Subject: [PATCH 1/4] Sqlite lock --- Sources/Database/DiskSqlite.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Database/DiskSqlite.swift b/Sources/Database/DiskSqlite.swift index 19ffba05e..bc241086b 100644 --- a/Sources/Database/DiskSqlite.swift +++ b/Sources/Database/DiskSqlite.swift @@ -7,11 +7,14 @@ public final class DiskSqlite: Sqlite { private var db: OpaquePointer? + private let lock = NSLock() + public init(path: String) { self.path = path } public func openDatabase() throws { + defer { lock.lock() } guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else { throw SQLiteError.openDatabase(path: path) } @@ -41,6 +44,7 @@ public final class DiskSqlite: Sqlite { } public func closeConnection() { + defer { lock.unlock() } sqlite3_close(db) } } From 92a6de8875320d3ffd889b8a2fa83b0d74cd5698 Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Tue, 7 Nov 2023 01:36:11 +0800 Subject: [PATCH 2/4] lock on every db access --- Sources/Database/DiskSqlite.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Sources/Database/DiskSqlite.swift b/Sources/Database/DiskSqlite.swift index bc241086b..1c13cb827 100644 --- a/Sources/Database/DiskSqlite.swift +++ b/Sources/Database/DiskSqlite.swift @@ -14,13 +14,18 @@ public final class DiskSqlite: Sqlite { } public func openDatabase() throws { - defer { lock.lock() } + defer { lock.unlock() } + lock.lock() + guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else { throw SQLiteError.openDatabase(path: path) } } public func query(sql: String) throws -> [Row] { + defer { lock.unlock() } + lock.lock() + var queryStatement: OpaquePointer? guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else { throw SQLiteError.queryPrepare(statement: sql) @@ -36,6 +41,9 @@ public final class DiskSqlite: Sqlite { } public func execute(sql: String) throws { + defer { lock.unlock() } + lock.lock() + var error: UnsafeMutablePointer? guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else { let message = error.map { String(cString: $0) } @@ -45,6 +53,8 @@ public final class DiskSqlite: Sqlite { public func closeConnection() { defer { lock.unlock() } + lock.lock() + sqlite3_close(db) } } From 5fb1043ec7e05c196a6a7f5caa9c8491e3ee4e66 Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Wed, 8 Nov 2023 20:25:49 +0800 Subject: [PATCH 3/4] Unfair lock --- Package.swift | 8 +-- Sources/Database/DatabaseImports.swift | 3 ++ Sources/Database/DiskSqlite.swift | 58 ++++++++++----------- Sources/WalletConnectUtils/UnfairLock.swift | 21 ++++++++ 4 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 Sources/Database/DatabaseImports.swift create mode 100644 Sources/WalletConnectUtils/UnfairLock.swift diff --git a/Package.swift b/Package.swift index 0f7ce4e77..93c74e302 100644 --- a/Package.swift +++ b/Package.swift @@ -37,15 +37,9 @@ let package = Package( .library( name: "WalletConnectNetworking", targets: ["WalletConnectNetworking"]), - .library( - name: "WalletConnectSync", - targets: ["WalletConnectSync"]), .library( name: "WalletConnectVerify", targets: ["WalletConnectVerify"]), - .library( - name: "WalletConnectHistory", - targets: ["WalletConnectHistory"]), .library( name: "WalletConnectModal", targets: ["WalletConnectModal"]), @@ -132,7 +126,7 @@ let package = Package( dependencies: ["WalletConnectUtils", "WalletConnectNetworking"]), .target( name: "Database", - dependencies: []), + dependencies: ["WalletConnectUtils"]), .target( name: "WalletConnectModal", dependencies: ["QRCode", "WalletConnectSign"], diff --git a/Sources/Database/DatabaseImports.swift b/Sources/Database/DatabaseImports.swift new file mode 100644 index 000000000..39a0c89b7 --- /dev/null +++ b/Sources/Database/DatabaseImports.swift @@ -0,0 +1,3 @@ +#if !CocoaPods +@_exported import WalletConnectUtils +#endif diff --git a/Sources/Database/DiskSqlite.swift b/Sources/Database/DiskSqlite.swift index 1c13cb827..8d7b77c49 100644 --- a/Sources/Database/DiskSqlite.swift +++ b/Sources/Database/DiskSqlite.swift @@ -7,54 +7,50 @@ public final class DiskSqlite: Sqlite { private var db: OpaquePointer? - private let lock = NSLock() + private let lock = UnfairLock() public init(path: String) { self.path = path } public func openDatabase() throws { - defer { lock.unlock() } - lock.lock() - - guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else { - throw SQLiteError.openDatabase(path: path) + try lock.locked { + guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else { + throw SQLiteError.openDatabase(path: path) + } } } public func query(sql: String) throws -> [Row] { - defer { lock.unlock() } - lock.lock() - - var queryStatement: OpaquePointer? - guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else { - throw SQLiteError.queryPrepare(statement: sql) - } - var rows: [Row] = [] - while sqlite3_step(queryStatement) == SQLITE_ROW { - let decoder = SqliteRowDecoder(statement: queryStatement) - guard let row = try? Row(decoder: decoder) else { continue } - rows.append(row) + return try lock.locked { + var queryStatement: OpaquePointer? + guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else { + throw SQLiteError.queryPrepare(statement: sql) + } + var rows: [Row] = [] + while sqlite3_step(queryStatement) == SQLITE_ROW { + let decoder = SqliteRowDecoder(statement: queryStatement) + guard let row = try? Row(decoder: decoder) else { continue } + rows.append(row) + } + sqlite3_finalize(queryStatement) + return rows } - sqlite3_finalize(queryStatement) - return rows } public func execute(sql: String) throws { - defer { lock.unlock() } - lock.lock() - - var error: UnsafeMutablePointer? - guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else { - let message = error.map { String(cString: $0) } - throw SQLiteError.exec(error: message) + try lock.locked { + var error: UnsafeMutablePointer? + guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else { + let message = error.map { String(cString: $0) } + throw SQLiteError.exec(error: message) + } } } public func closeConnection() { - defer { lock.unlock() } - lock.lock() - - sqlite3_close(db) + lock.locked { + sqlite3_close(db) + } } } diff --git a/Sources/WalletConnectUtils/UnfairLock.swift b/Sources/WalletConnectUtils/UnfairLock.swift new file mode 100644 index 000000000..3e22d97d9 --- /dev/null +++ b/Sources/WalletConnectUtils/UnfairLock.swift @@ -0,0 +1,21 @@ +import Foundation + +public final class UnfairLock { + private var lock: UnsafeMutablePointer + + public init() { + lock = UnsafeMutablePointer.allocate(capacity: 1) + lock.initialize(to: os_unfair_lock()) + } + + deinit { + lock.deallocate() + } + + @discardableResult + public func locked(_ f: () throws -> ReturnValue) rethrows -> ReturnValue { + os_unfair_lock_lock(lock) + defer { os_unfair_lock_unlock(lock) } + return try f() + } +} From cfe81d670a6d44445ad87752cf400abeecbca2fb Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Wed, 8 Nov 2023 20:28:36 +0800 Subject: [PATCH 4/4] Package.swift reverted --- Package.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Package.swift b/Package.swift index 93c74e302..dcfa42b87 100644 --- a/Package.swift +++ b/Package.swift @@ -37,9 +37,15 @@ let package = Package( .library( name: "WalletConnectNetworking", targets: ["WalletConnectNetworking"]), + .library( + name: "WalletConnectSync", + targets: ["WalletConnectSync"]), .library( name: "WalletConnectVerify", targets: ["WalletConnectVerify"]), + .library( + name: "WalletConnectHistory", + targets: ["WalletConnectHistory"]), .library( name: "WalletConnectModal", targets: ["WalletConnectModal"]),