Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Child Transaction Optimization #222

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extension DiskPersistence {
unowned let persistence: DiskPersistence

unowned let parent: Transaction?
var childTransactions: [Transaction] = []
weak var lastReadWriteChildTransaction: Transaction?

private(set) var task: Task<Void, Error>!
let options: UnsafeTransactionOptions
Expand Down Expand Up @@ -133,7 +133,6 @@ extension DiskPersistence {
deletedRootObjects.removeAll()
deletedIndexes.removeAll()
deletedPages.removeAll()
childTransactions.removeAll()
}

if let parent {
Expand Down Expand Up @@ -231,28 +230,30 @@ extension DiskPersistence {
@_inheritActorContext handler: @Sendable @escaping (_ transaction: Transaction, _ isDurable: Bool) async throws -> T
) async -> (Transaction, Task<T, Error>) {
assert(!self.options.contains(.readOnly) || options.contains(.readOnly), "A child transaction was declared read-write, even though its parent was read-only!")
let transaction = Transaction(
let childTransaction = Transaction(
persistence: persistence,
parent: self,
actionName: nil,
options: options
)

/// Get the last non-concurrent transaction from the list. Note that disk persistence currently does not support concurrent idempotent transactions.
let lastChild = childTransactions.last { !$0.options.contains(.readOnly) }
childTransactions.append(transaction)
let lastChild = lastReadWriteChildTransaction
if !childTransaction.options.contains(.readOnly) {
lastReadWriteChildTransaction = childTransaction
}

let task = await transaction.attachTask(options: options) {
let task = await childTransaction.attachTask(options: options) {
try self.checkIsActive()

/// If the transaction is not read only, wait for the last transaction to properly finish before starting the next one.
if !options.contains(.readOnly) {
_ = try? await lastChild?.task.value
}
return try await handler(transaction, false)
return try await handler(childTransaction, false)
}

return (transaction, task)
return (childTransaction, task)
}

func rootObject(for datastoreKey: DatastoreKey) async throws -> Datastore.RootObject? {
Expand Down
Loading