-
-
Notifications
You must be signed in to change notification settings - Fork 530
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
Transaction 2 #199
Transaction 2 #199
Conversation
Good morning. Thank you again for the pioneering effort. I quite liked the original Back to square 1, was that the |
My first transaction implementation was inconplete, wrapper inside a Mutex it wasn't possible to have a Transaction type that didn't lived inside a pinboxed closure, and it wasn't possible to use it for streaming, because the mutable reference was limited by the Mutex. As I already said, but maybe yesterday evening I was too tired to be expressive, this PR is to discuss the road, I think the improvement is huge and, if only UnsafeCell is the problem, I can try to find another solution, maybe with GhostCell |
Thank you for the clarification. I understand that. Well, I have read the |
Well, the normal connection has a completely safe implementation also now, the same applies to InnerConnection, UnsafeCell is only inside DatabaseTransaction. |
I've checked a few things:
The main problem with actual implementation, is that inside Another hidden bomb is Sqlite: Sqlite sqlx connections aren't Sync. A lesson learnt from this PR is that sqlx Transactions can be easily de-structured, sqlx has a TransactionManager trait that manages what's executed on a connection to make it a transaction, therefore you don't really need a sqlx Transaction object, you just need a sqlx connection object and to know which TransactionManager implementation call. |
Another test I've done is to impl ConnectionTrait on &DatabaseConnection and &mut DatabaseTransaction, this way we would be able to differentiate on mutability only where needed. |
Thank you for the hard work indeed. Yes, we'd better scrap the 'transaction in a closure' API or only provide it as a convenient helper, but not as the universal solution. May be we should return to the start, commit & rollback style, where 'start' returns an owned Transaction object wrapping a connection with Arc< Mutex > (thus can be mutated), whose lifetime shall not exceeds the parent pool, and automatically rollback if goes out of scope. That'd still be 'flat'? |
With Arcmutex you mean a normal |
My bad for the poor formatting. Yes, otherwise there is no other way to hide the mutability I suppose. |
Well, it could actually work... |
Hopefully it'd work. |
I'm trying right now, but in fact now I remember why I didn't considered that technique: using a Mutex you can't "leak" a reference, therefore you can't have streams
Well, this branch is based on streams that is based on transaction-1... |
I tried to think about that yesterday. |
I have an idea, maybe today I'll be able to test it, I'll let you know |
Well, the only test failed is on the Rocket example, that I haven't touched, for reasons not related to my changes... DatabaseTransaction contains an There is still an uncovered path, and it's on drop of a nested transaction, actually there is an |
Thank you so much for the hard work! |
My tests are all green, let me know if you've any doubt |
Yup, I am making the final Other than that, about the MockConnection, I hope that it can mimick the behavior, say there is a transaction with 2 statements executed on a MockConnection, the assert_eq!(
db.into_transaction_log(),
vec![
Transaction::many([
Statement::from_sql_and_values(
DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
vec![1u64.into()]
),
Statement::from_sql_and_values(
DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
vec![]
)
])
]
); I am still thinking of how to implement this, perhaps a |
Yes, streams are implemented here.
At the moment a transaction for a Mocked connection is transparent, but yes, a buffer could be a good solution, merging it on commit and dropping it on rollback |
Can you explain briefly what the |
|
MutexGuard is the owner of the mutable reference coming from Mutex, once MutexGuard is dropped, Mutex is unlocked. |
So, while the But what's the difference to |
QueryStream has an owned connection inside, taken directly from the pool. Like any other operation outside a Transaction, a new connection is taken from the pool every time, used and then returned to the pool. QueryStream is little different, it keeps the connection for the stream lifetime |
Thank you for the explanation. It helped a lot. |
I know this is a pretty new PR, and is likely to undergo many changes until merge, but has thought been put into transaction isolation support? |
Thank you for raising. Sure we will get to that. |
|
We could support transaction isolation if SQLx have it |
#142
This is a HUGE rework of Transactions, that permits nested transactions, streams in transactions, etc...
There is unsafe code, not much, should be safe, but needs a lot of testing.
To avoid unsafe code we'll probably need a design rework.
This PR is based on the streams one, probably will be a mess of conflicts, I just need to know what you think about and decide how to go on