Path: blob/main/SignalServiceKit/Storage/Database/SDSDatabaseStorage/V2/DBTransaction.swift
1 views
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
public import GRDB
public import LibSignalClient
@objc
public class DBReadTransaction: NSObject {
public let database: Database
public let startDate: MonotonicDate
init(database: Database) {
self.database = database
self.startDate = MonotonicDate()
}
}
@objc
public class DBWriteTransaction: DBReadTransaction, LibSignalClient.StoreContext {
private enum TransactionState {
case open
case finalizing
case finalized
}
typealias FinalizationBlock = (DBWriteTransaction) -> Void
typealias CompletionBlock = () -> Void
private var transactionState: TransactionState
private var finalizationBlocks: [String: FinalizationBlock]
private(set) var completionBlocks: [CompletionBlock]
override init(database: Database) {
self.transactionState = .open
self.finalizationBlocks = [:]
self.completionBlocks = []
super.init(database: database)
}
deinit {
owsAssertDebug(
transactionState == .finalized,
"Write transaction deallocated without finalization!",
)
}
// MARK: -
func finalizeTransaction() {
guard transactionState == .open else {
owsFailDebug("Write transaction finalized multiple times!")
return
}
transactionState = .finalizing
for (_, finalizationBlock) in finalizationBlocks {
finalizationBlock(self)
}
finalizationBlocks.removeAll()
transactionState = .finalized
}
// MARK: -
/// Schedule the given block to run when this transaction is finalized.
///
/// - Important
/// `block` must not capture any database models, as they may no longer be
/// valid by time the transaction finalizes.
func addFinalizationBlock(key: String, block: @escaping FinalizationBlock) {
finalizationBlocks[key] = block
}
/// Run the given block synchronously after the transaction is finalized.
public func addSyncCompletion(block: @escaping () -> Void) {
completionBlocks.append(block)
}
}
// MARK: -
public extension LibSignalClient.StoreContext {
var asTransaction: DBWriteTransaction {
return self as! DBWriteTransaction
}
}