Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0d0435f

Browse files
committed
Start on prepare
1 parent 8c3770b commit 0d0435f

File tree

8 files changed

+153
-17
lines changed

8 files changed

+153
-17
lines changed

tokio-postgres/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ tokio-codec = "0.1"
4444
tokio-io = "0.1"
4545
tokio-tcp = "0.1"
4646
tokio-timer = "0.2"
47+
want = "0.0.5"
4748

4849
[target.'cfg(unix)'.dependencies]
4950
tokio-uds = "0.2"

tokio-postgres/src/lib.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ extern crate tokio_codec;
77
extern crate tokio_io;
88
extern crate tokio_tcp;
99
extern crate tokio_timer;
10+
extern crate want;
1011

1112
#[macro_use]
1213
extern crate futures;
@@ -18,12 +19,13 @@ extern crate state_machine_future;
1819
#[cfg(unix)]
1920
extern crate tokio_uds;
2021

21-
use futures::sync::mpsc;
2222
use futures::{Async, Future, Poll};
2323
use std::io;
2424

2525
#[doc(inline)]
26-
pub use postgres_shared::{error, params};
26+
pub use postgres_shared::stmt::Column;
27+
#[doc(inline)]
28+
pub use postgres_shared::{error, params, types};
2729
#[doc(inline)]
2830
pub use postgres_shared::{CancelData, Notification};
2931

@@ -46,12 +48,22 @@ fn disconnected() -> Error {
4648
))
4749
}
4850

49-
pub struct Client(mpsc::Sender<proto::Request>);
51+
pub struct Client(proto::Client);
5052

5153
impl Client {
5254
pub fn connect(params: ConnectParams) -> Handshake {
5355
Handshake(proto::HandshakeFuture::new(params))
5456
}
57+
58+
/// Polls to to determine whether the connection is ready to send new requests to the backend.
59+
///
60+
/// Requests are unboundedly buffered to enable pipelining, but this risks unbounded memory consumption if requests
61+
/// are produced at a faster pace than the backend can process. This method can be used to cooperatively "throttle"
62+
/// request creation. Specifically, it returns ready when the connection has sent any queued requests and is waiting
63+
/// on new requests from the client.
64+
pub fn poll_ready(&mut self) -> Poll<(), Error> {
65+
self.0.poll_ready()
66+
}
5567
}
5668

5769
pub struct Connection(proto::Connection);
@@ -82,8 +94,8 @@ impl Future for Handshake {
8294
type Error = Error;
8395

8496
fn poll(&mut self) -> Poll<(Client, Connection), Error> {
85-
let (sender, connection) = try_ready!(self.0.poll());
97+
let (client, connection) = try_ready!(self.0.poll());
8698

87-
Ok(Async::Ready((Client(sender), Connection(connection))))
99+
Ok(Async::Ready((Client(client), Connection(connection))))
88100
}
89101
}

tokio-postgres/src/proto/client.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use futures::sync::mpsc;
2+
use futures::Poll;
3+
use postgres_protocol::message::backend::Message;
4+
use want::Giver;
5+
6+
use disconnected;
7+
use error::Error;
8+
use proto::connection::Request;
9+
10+
pub struct Client {
11+
sender: mpsc::UnboundedSender<Request>,
12+
giver: Giver,
13+
}
14+
15+
impl Client {
16+
pub fn new(sender: mpsc::UnboundedSender<Request>, giver: Giver) -> Client {
17+
Client { sender, giver }
18+
}
19+
20+
pub fn poll_ready(&mut self) -> Poll<(), Error> {
21+
self.giver.poll_want().map_err(|_| disconnected())
22+
}
23+
24+
pub fn send(&mut self, messages: Vec<u8>) -> Result<mpsc::Receiver<Message>, Error> {
25+
let (sender, receiver) = mpsc::channel(0);
26+
self.giver.give();
27+
self.sender
28+
.unbounded_send(Request { messages, sender })
29+
.map(|_| receiver)
30+
.map_err(|_| disconnected())
31+
}
32+
}

tokio-postgres/src/proto/connection.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use postgres_protocol::message::frontend;
55
use std::collections::{HashMap, VecDeque};
66
use std::io;
77
use tokio_codec::Framed;
8+
use want::Taker;
89

910
use error::{self, Error};
1011
use proto::codec::PostgresCodec;
@@ -27,7 +28,8 @@ pub struct Connection {
2728
stream: Framed<Socket, PostgresCodec>,
2829
cancel_data: CancelData,
2930
parameters: HashMap<String, String>,
30-
receiver: mpsc::Receiver<Request>,
31+
receiver: mpsc::UnboundedReceiver<Request>,
32+
taker: Taker,
3133
pending_request: Option<Vec<u8>>,
3234
pending_response: Option<Message>,
3335
responses: VecDeque<mpsc::Sender<Message>>,
@@ -39,13 +41,15 @@ impl Connection {
3941
stream: Framed<Socket, PostgresCodec>,
4042
cancel_data: CancelData,
4143
parameters: HashMap<String, String>,
42-
receiver: mpsc::Receiver<Request>,
44+
receiver: mpsc::UnboundedReceiver<Request>,
45+
taker: Taker,
4346
) -> Connection {
4447
Connection {
4548
stream,
4649
cancel_data,
4750
parameters,
4851
receiver,
52+
taker,
4953
pending_request: None,
5054
pending_response: None,
5155
responses: VecDeque::new(),
@@ -76,7 +80,10 @@ impl Connection {
7680
Async::Ready(None) => {
7781
return Err(Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)));
7882
}
79-
Async::NotReady => return Ok(()),
83+
Async::NotReady => {
84+
self.taker.want();
85+
return Ok(());
86+
}
8087
};
8188

8289
let message = match message {
@@ -100,7 +107,7 @@ impl Connection {
100107
},
101108
};
102109

103-
let ready = match message {
110+
let request_complete = match message {
104111
Message::ReadyForQuery(_) => true,
105112
_ => false,
106113
};
@@ -109,7 +116,7 @@ impl Connection {
109116
// if the receiver's hung up we still need to page through the rest of the messages
110117
// designated to it
111118
Ok(AsyncSink::Ready) | Err(_) => {
112-
if !ready {
119+
if !request_complete {
113120
self.responses.push_front(sender);
114121
}
115122
}

tokio-postgres/src/proto/handshake.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ use state_machine_future::RentToOwn;
1010
use std::collections::HashMap;
1111
use std::io;
1212
use tokio_codec::Framed;
13+
use want;
1314

1415
use error::{self, Error};
1516
use params::{ConnectParams, User};
17+
use proto::client::Client;
1618
use proto::codec::PostgresCodec;
17-
use proto::connection::{Connection, Request};
19+
use proto::connection::Connection;
1820
use proto::socket::{ConnectFuture, Socket};
1921
use {bad_response, disconnected, CancelData};
2022

@@ -60,7 +62,7 @@ pub enum Handshake {
6062
parameters: HashMap<String, String>,
6163
},
6264
#[state_machine_future(ready)]
63-
Finished((mpsc::Sender<Request>, Connection)),
65+
Finished((Client, Connection)),
6466
#[state_machine_future(error)]
6567
Failed(Error),
6668
}
@@ -281,10 +283,17 @@ impl PollHandshake for Handshake {
281283
let cancel_data = state.cancel_data.ok_or_else(|| {
282284
io::Error::new(io::ErrorKind::InvalidData, "BackendKeyData message missing")
283285
})?;
284-
let (sender, receiver) = mpsc::channel(0);
285-
let connection =
286-
Connection::new(state.stream, cancel_data, state.parameters, receiver);
287-
transition!(Finished((sender, connection)))
286+
let (sender, receiver) = mpsc::unbounded();
287+
let (giver, taker) = want::new();
288+
let client = Client::new(sender, giver);
289+
let connection = Connection::new(
290+
state.stream,
291+
cancel_data,
292+
state.parameters,
293+
receiver,
294+
taker,
295+
);
296+
transition!(Finished((client, connection)))
288297
}
289298
Some(Message::ErrorResponse(body)) => return Err(error::__db(body)),
290299
Some(Message::NoticeResponse(_)) => {}

tokio-postgres/src/proto/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
mod client;
12
mod codec;
23
mod connection;
34
mod handshake;
5+
mod prepare;
46
mod socket;
7+
mod statement;
58

9+
pub use proto::client::Client;
610
pub use proto::codec::PostgresCodec;
7-
pub use proto::connection::{Connection, Request};
11+
pub use proto::connection::Connection;
812
pub use proto::handshake::HandshakeFuture;
13+
pub use proto::prepare::PrepareFuture;
914
pub use proto::socket::Socket;
15+
pub use statement::Statement;

tokio-postgres/src/proto/prepare.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use futures::sync::mpsc;
2+
use postgres_protocol::message::backend::Message;
3+
4+
use error::Error;
5+
use proto::connection::Request;
6+
use proto::statement::Statement;
7+
8+
#[derive(StateMachineFuture)]
9+
pub enum Prepare {
10+
#[state_machine_future(start)]
11+
Start {
12+
sender: mpsc::UnboundedSender<Request>,
13+
receiver: Result<mpsc::Receiver<Message>, Error>,
14+
name: String,
15+
},
16+
#[state_machine_future(ready)]
17+
Finished(Statement),
18+
#[state_machine_future(error)]
19+
Failed(Error),
20+
}

tokio-postgres/src/proto/statement.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use futures::sync::mpsc;
2+
use postgres_protocol::message::frontend;
3+
use postgres_shared::stmt::Column;
4+
5+
use proto::connection::Request;
6+
use types::Type;
7+
8+
pub struct Statement {
9+
sender: mpsc::UnboundedSender<Request>,
10+
name: String,
11+
params: Vec<Type>,
12+
columns: Vec<Column>,
13+
}
14+
15+
impl Drop for Statement {
16+
fn drop(&mut self) {
17+
let mut buf = vec![];
18+
frontend::close(b'S', &self.name, &mut buf).expect("statement name not valid");
19+
let (sender, _) = mpsc::channel(0);
20+
self.sender.unbounded_send(Request {
21+
messages: buf,
22+
sender,
23+
});
24+
}
25+
}
26+
27+
impl Statement {
28+
pub fn new(
29+
sender: mpsc::UnboundedReceiver<Request>,
30+
name: String,
31+
params: Vec<Type>,
32+
columns: Vec<Column>,
33+
) -> Statement {
34+
Statement {
35+
sender,
36+
name,
37+
params,
38+
columns,
39+
}
40+
}
41+
42+
pub fn params(&self) -> &[Type] {
43+
&self.params
44+
}
45+
46+
pub fn columns(&self) -> &[Column] {
47+
&self.columns
48+
}
49+
}

0 commit comments

Comments
 (0)