From fe0420d70e955026b0126bf995a8806fb0103d19 Mon Sep 17 00:00:00 2001 From: Anthony Drendel Date: Wed, 31 Jan 2024 23:11:43 +0100 Subject: [PATCH 1/4] Use self-hosted runner --- .github/workflows/ci.yml | 4 +--- Sources/SQLite/SQLiteDatabase.swift | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ce72f7..99ffffd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,11 +4,9 @@ on: push jobs: test: - runs-on: macos-13 + runs-on: self-hosted steps: - uses: actions/checkout@v3 - - name: Select Xcode 15 - run: sudo xcode-select -s /Applications/Xcode_15.0.app - name: Test run: swift test diff --git a/Sources/SQLite/SQLiteDatabase.swift b/Sources/SQLite/SQLiteDatabase.swift index 4cb95d5..4c708de 100644 --- a/Sources/SQLite/SQLiteDatabase.swift +++ b/Sources/SQLite/SQLiteDatabase.swift @@ -648,9 +648,7 @@ private extension SQLiteDatabase { // automatic vacuuming. // // https://swiftpackageindex.com/groue/grdb.swift/v6.24.2/documentation/grdb/databasesharing#How-to-limit-the-SQLITEBUSY-error - config.defaultTransactionKind = isInMemory - ? .deferred - : .immediate + config.defaultTransactionKind = .immediate config.busyMode = .timeout(busyTimeout) config.observesSuspensionNotifications = true config.maximumReaderCount = max( From b3de32e2c368a4bb294ce63cb044cf900db80de2 Mon Sep 17 00:00:00 2001 From: Anthony Drendel Date: Wed, 31 Jan 2024 23:22:34 +0100 Subject: [PATCH 2/4] Use GitHub runner --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99ffffd..7129d66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,9 +4,12 @@ on: push jobs: test: - runs-on: self-hosted - + runs-on: macos-13 + steps: - uses: actions/checkout@v3 + - name: Select Xcode 15 + run: sudo xcode-select -s /Applications/Xcode_15.0.app - name: Test run: swift test + From fa79c785e0d8ce5f4a6f2b08f8c281a5e3261289 Mon Sep 17 00:00:00 2001 From: Anthony Drendel Date: Thu, 1 Feb 2024 14:28:50 +0100 Subject: [PATCH 3/4] Fix errors when running PRAGMA --- Sources/SQLite/SQLiteDatabase.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/SQLite/SQLiteDatabase.swift b/Sources/SQLite/SQLiteDatabase.swift index 4c708de..862af02 100644 --- a/Sources/SQLite/SQLiteDatabase.swift +++ b/Sources/SQLite/SQLiteDatabase.swift @@ -339,7 +339,7 @@ public extension SQLiteDatabase { @discardableResult func execute(raw sql: SQL) throws -> [SQLiteRow] { do { - return try database.writer.write { db in + return try database.writer.barrierWriteWithoutTransaction { db in try db.execute(raw: sql) } } catch { @@ -644,8 +644,7 @@ private extension SQLiteDatabase { config.journalMode = isInMemory ? .default : .wal // NOTE: GRDB recommends `defaultTransactionKind` be set // to `.immediate` in order to prevent `SQLITE_BUSY` - // errors. Using `.immediate` appears to disable - // automatic vacuuming. + // errors. // // https://swiftpackageindex.com/groue/grdb.swift/v6.24.2/documentation/grdb/databasesharing#How-to-limit-the-SQLITEBUSY-error config.defaultTransactionKind = .immediate From 892b15a9e89b48664c230e42f140a9a994861a3c Mon Sep 17 00:00:00 2001 From: Anthony Drendel Date: Thu, 1 Feb 2024 15:43:55 +0100 Subject: [PATCH 4/4] Fix issues with immediate transactions --- Sources/SQLite/SQLiteDatabase.swift | 20 +++++++++++++++++--- Tests/SQLiteTests/SQLiteDatabaseTests.swift | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Sources/SQLite/SQLiteDatabase.swift b/Sources/SQLite/SQLiteDatabase.swift index 862af02..81679a1 100644 --- a/Sources/SQLite/SQLiteDatabase.swift +++ b/Sources/SQLite/SQLiteDatabase.swift @@ -111,6 +111,20 @@ public final class SQLiteDatabase: DatabaseProtocol, @unchecked Sendable { ) } + public func truncate() throws { + switch database { + case let .pool(pool): + try pool.writeWithoutTransaction { db in + _ = try db.execute(raw: "PRAGMA wal_checkpoint(TRUNCATE);") + } + + case let .queue(queue): + try queue.writeWithoutTransaction { db in + _ = try db.execute(raw: "PRAGMA wal_checkpoint(TRUNCATE);") + } + } + } + // NOTE: This function is only really meant to be called in tests. public func close() throws { changeNotifier.stop() @@ -275,7 +289,7 @@ public extension SQLiteDatabase { @discardableResult func execute(raw sql: SQL) async throws -> [SQLiteRow] { do { - return try await database.writer.write { db in + return try await database.writer.writeWithoutTransaction { db in try db.execute(raw: sql) } } catch { @@ -339,7 +353,7 @@ public extension SQLiteDatabase { @discardableResult func execute(raw sql: SQL) throws -> [SQLiteRow] { do { - return try database.writer.barrierWriteWithoutTransaction { db in + return try database.writer.writeWithoutTransaction { db in try db.execute(raw: sql) } } catch { @@ -767,7 +781,7 @@ private enum Database { arguments: SQLiteArguments = [:] ) throws { do { - try writer.write { db in + try writer.writeWithoutTransaction { db in try db.write(sql, arguments: arguments) } } catch { diff --git a/Tests/SQLiteTests/SQLiteDatabaseTests.swift b/Tests/SQLiteTests/SQLiteDatabaseTests.swift index bf9c7a4..67b3651 100644 --- a/Tests/SQLiteTests/SQLiteDatabaseTests.swift +++ b/Tests/SQLiteTests/SQLiteDatabaseTests.swift @@ -253,6 +253,27 @@ final class SQLiteDatabaseTests: XCTestCase { } } + func testCheckpointUsingTruncate() throws { + try Sandbox.execute { directory in + let path = directory.appendingPathComponent("test.db").path + let db = try SQLiteDatabase(path: path) + defer { try? db.close() } + + try db.execute(raw: _createTableWithBlob) + + try db.inTransaction { db in + for index in 0 ..< 100 { + let args: SQLiteArguments = [ + "id": .integer(Int64(index)), "data": .data(_textData), + ] + try db.write(_insertIDAndData, arguments: args) + } + } + + try db.truncate() + } + } + func testCreateTable() throws { XCTAssertNoThrow(try database.execute(raw: _createTableWithBlob)) let tableNames = try database.tables()