-
-
Notifications
You must be signed in to change notification settings - Fork 486
pipelining should document (and maybe the client should provide?) ordering guarantees #930
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
Comments
The work for a query will start on the first call to poll, but using query with a string rather than a I would additionally not recommend trying to pipeline requests with the creation of a transaction - if the If you are sure you need to pipeline these queries for performance reasons, I would at least recommend pre-prepared statements to avoid multiple round trips. At that point, you should be guaranteed that the queries will be sent in order of the first poll of their future. |
The BEGIN example was contrived. My actual problem was I was already in a transaction and needed to execute some queries in order and wanted to pipeline them. All my statements are already prepared. I wanted to use pipelining to stop waiting for network roundtrips for each Bind/Describe/Execute batch, but I don't think there's a way to do that correctly. |
If the statements are already prepared, then the queries should be guaranteed to execute in the order they were first polled, and it looks like the futures crate's try_join does poll in-order. If that's not the case, then it'd be great if you could put together a small self contained example of that and I can look into it. |
rust-postgres/tokio-postgres/src/client.rs Line 370 in a624282
query_raw before the .send , which I think means even if try_join was polling its arguments in order, the actual query execution could still be in another order.
|
into_statement returns a future that immediately resolves when working with a
|
My argument is that there should be documentation that either guarantees or does not guarantee statement execution order during pipelining because relying on a bunch of implementation details that don't seem to be documented guarantees is not helpful to users trying to write safe, fast code. Knowing exactly how async, await, try_for, and tokio_postgres internals work is a significant bar, and they can also change at any time. try_join for example happens to execute in a certain way, but does not guarantee it. tokio_postgres happens to have at least one internal await point that immediately resolves. Are there other await points before the send? Even if there weren't, does the send ordering have any guarantees on the receive side? I couldn't find those in the tokio docs. Knowing exactly what happens during immediately resolving await points also feels like some rust obscura that we all probably get subtly wrong sometimes. If we want pipelining to make things go fast, then it should document whether or not it comes with ordering guarantees so users can use it safely. |
Queries are executed in order, as the docs note: https://docs.rs/tokio-postgres/latest/tokio_postgres/#pipelining. |
Ah, the section above it about behavior does say this
This is about half of what I wanted, but I was looking for it in the wrong place. I do think the above sentence could be improved with an API change that guarantees the order at time of calling, not polling. |
Attached is a program that doesn't execute statements in order of first poll. It achieves this by first using an unprepared statement which fires off a prepare request. The above comment about immediately resolving the to_statement future is not true for unprepared statements. In general it seems the documented claim only holds if there are no string statements preceding prepared statements in a join batch. This program fails with a primary key error due to the insert happening with an existing key, because it is executed before the delete.
|
Yeah, that was the first thing I mentioned in my first post above. If the statement is not already prepared, executing it requires two query/response pairs and only the first will happen before later queries you're pipelining. |
Currently it does not look like pipelining of dependent queries can really be used. None of the usual futures utilities like try_join and FuturesOrdered guarantee the order in which the futures are polled. This could be made much simpler by having |
After looking at the source code I think we could have a variant of |
I'v also opened rust-lang/futures-rs#2674 to ask for guarantees from FuturesUnordered. |
I have very similar problem with pipelining. I have stream of async call to DB that I want to speed up. pipelining seems like big win for this. But it's hard for me to decide if the code below is sound. Unfortunately order of execute has matter. // `iter` - contains items to upsert to postgres
tokio_stream::iter(
iter.remainder()
.iter()
.map(|one| async { self.store_one(client, one).await }),
)
.buffer_unordered(MAX_CONCURRENT)
.try_collect::<Vec<_>>()
.await
.map(drop) |
I'm having the same problem. Ideally, I should be able to pipeline queries where the latter is dependent on the former, since ultimately they will execute sequentially. Having the order of future execution not be in order kills that capability. |
Prepare the statements before executing them and they will run in order. |
The pipeline documentation should perhaps describe that there are no ordering guarantees when pipelining queries. For example:
Will not always execute f2 in the transaction started by f1 because
query
is an async fn and so will not execute anything until poll'd the first time, which isn't guaranteed bytry_join
. This is a subtle and easy error to make (I made it).One thing that'd be real great is if the various
query
functions were sync and returned aimpl Future
such that they could guarantee query execution order in the order they were called. It seems like that could be achieved if hand waving the order of messages in therecv
side of the InnerClient'ssender
channel is the same as thesend
order somehow.The text was updated successfully, but these errors were encountered: