Don't hold strong references in statements

There's no need for the connection to stay open until statements drop -
they'll be cleaned up anyway once the connection dies.
This commit is contained in:
Steven Fackler 2018-07-07 16:43:07 -07:00
parent 1788a03baa
commit 3955d26c20
9 changed files with 160 additions and 128 deletions

View File

@ -4,7 +4,7 @@ use postgres_protocol;
use postgres_protocol::message::backend::Message; use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend; use postgres_protocol::message::frontend;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::{Arc, Weak};
use disconnected; use disconnected;
use error::{self, Error}; use error::{self, Error};
@ -15,49 +15,91 @@ use proto::query::QueryStream;
use proto::statement::Statement; use proto::statement::Statement;
use types::{IsNull, Oid, ToSql, Type}; use types::{IsNull, Oid, ToSql, Type};
pub struct PendingRequest { pub struct PendingRequest(Result<Vec<u8>, Error>);
sender: mpsc::UnboundedSender<Request>,
messages: Result<Vec<u8>, Error>,
}
impl PendingRequest { pub struct WeakClient(Weak<Inner>);
pub fn send(self) -> Result<mpsc::Receiver<Message>, Error> {
let messages = self.messages?; impl WeakClient {
let (sender, receiver) = mpsc::channel(0); pub fn upgrade(&self) -> Option<Client> {
self.sender self.0.upgrade().map(Client)
.unbounded_send(Request { messages, sender })
.map(|_| receiver)
.map_err(|_| disconnected())
} }
} }
pub struct State { struct State {
pub types: HashMap<Oid, Type>, types: HashMap<Oid, Type>,
pub typeinfo_query: Option<Statement>, typeinfo_query: Option<Statement>,
pub typeinfo_enum_query: Option<Statement>, typeinfo_enum_query: Option<Statement>,
pub typeinfo_composite_query: Option<Statement>, typeinfo_composite_query: Option<Statement>,
} }
#[derive(Clone)] struct Inner {
pub struct Client { state: Mutex<State>,
pub state: Arc<Mutex<State>>,
sender: mpsc::UnboundedSender<Request>, sender: mpsc::UnboundedSender<Request>,
} }
#[derive(Clone)]
pub struct Client(Arc<Inner>);
impl Client { impl Client {
pub fn new(sender: mpsc::UnboundedSender<Request>) -> Client { pub fn new(sender: mpsc::UnboundedSender<Request>) -> Client {
Client { Client(Arc::new(Inner {
state: Arc::new(Mutex::new(State { state: Mutex::new(State {
types: HashMap::new(), types: HashMap::new(),
typeinfo_query: None, typeinfo_query: None,
typeinfo_enum_query: None, typeinfo_enum_query: None,
typeinfo_composite_query: None, typeinfo_composite_query: None,
})), }),
sender, sender,
} }))
} }
pub fn prepare(&mut self, name: String, query: &str, param_types: &[Type]) -> PrepareFuture { pub fn downgrade(&self) -> WeakClient {
WeakClient(Arc::downgrade(&self.0))
}
pub fn cached_type(&self, oid: Oid) -> Option<Type> {
self.0.state.lock().types.get(&oid).cloned()
}
pub fn cache_type(&self, ty: &Type) {
self.0.state.lock().types.insert(ty.oid(), ty.clone());
}
pub fn typeinfo_query(&self) -> Option<Statement> {
self.0.state.lock().typeinfo_query.clone()
}
pub fn set_typeinfo_query(&self, statement: &Statement) {
self.0.state.lock().typeinfo_query = Some(statement.clone());
}
pub fn typeinfo_enum_query(&self) -> Option<Statement> {
self.0.state.lock().typeinfo_enum_query.clone()
}
pub fn set_typeinfo_enum_query(&self, statement: &Statement) {
self.0.state.lock().typeinfo_enum_query = Some(statement.clone());
}
pub fn typeinfo_composite_query(&self) -> Option<Statement> {
self.0.state.lock().typeinfo_composite_query.clone()
}
pub fn set_typeinfo_composite_query(&self, statement: &Statement) {
self.0.state.lock().typeinfo_composite_query = Some(statement.clone());
}
pub fn send(&self, request: PendingRequest) -> Result<mpsc::Receiver<Message>, Error> {
let messages = request.0?;
let (sender, receiver) = mpsc::channel(0);
self.0
.sender
.unbounded_send(Request { messages, sender })
.map(|_| receiver)
.map_err(|_| disconnected())
}
pub fn prepare(&self, name: String, query: &str, param_types: &[Type]) -> PrepareFuture {
let pending = self.pending(|buf| { let pending = self.pending(|buf| {
frontend::parse(&name, query, param_types.iter().map(|t| t.oid()), buf)?; frontend::parse(&name, query, param_types.iter().map(|t| t.oid()), buf)?;
frontend::describe(b'S', &name, buf)?; frontend::describe(b'S', &name, buf)?;
@ -65,17 +107,28 @@ impl Client {
Ok(()) Ok(())
}); });
PrepareFuture::new(pending, self.sender.clone(), name, self.clone()) PrepareFuture::new(self.clone(), pending, name)
} }
pub fn execute(&mut self, statement: &Statement, params: &[&ToSql]) -> ExecuteFuture { pub fn execute(&self, statement: &Statement, params: &[&ToSql]) -> ExecuteFuture {
let pending = self.pending_execute(statement, params); let pending = self.pending_execute(statement, params);
ExecuteFuture::new(pending, statement.clone()) ExecuteFuture::new(self.clone(), pending, statement.clone())
} }
pub fn query(&mut self, statement: &Statement, params: &[&ToSql]) -> QueryStream { pub fn query(&self, statement: &Statement, params: &[&ToSql]) -> QueryStream {
let pending = self.pending_execute(statement, params); let pending = self.pending_execute(statement, params);
QueryStream::new(pending, statement.clone()) QueryStream::new(self.clone(), pending, statement.clone())
}
pub fn close_statement(&self, name: &str) {
let mut buf = vec![];
frontend::close(b'S', name, &mut buf).expect("statement name not valid");
frontend::sync(&mut buf);
let (sender, _) = mpsc::channel(0);
let _ = self.0.sender.unbounded_send(Request {
messages: buf,
sender,
});
} }
fn pending_execute(&self, statement: &Statement, params: &[&ToSql]) -> PendingRequest { fn pending_execute(&self, statement: &Statement, params: &[&ToSql]) -> PendingRequest {
@ -109,9 +162,6 @@ impl Client {
F: FnOnce(&mut Vec<u8>) -> Result<(), Error>, F: FnOnce(&mut Vec<u8>) -> Result<(), Error>,
{ {
let mut buf = vec![]; let mut buf = vec![];
PendingRequest { PendingRequest(messages(&mut buf).map(|()| buf))
sender: self.sender.clone(),
messages: messages(&mut buf).map(|()| buf),
}
} }
} }

View File

@ -4,7 +4,7 @@ use postgres_protocol::message::backend::Message;
use state_machine_future::RentToOwn; use state_machine_future::RentToOwn;
use error::{self, Error}; use error::{self, Error};
use proto::client::PendingRequest; use proto::client::{Client, PendingRequest};
use proto::statement::Statement; use proto::statement::Statement;
use {bad_response, disconnected}; use {bad_response, disconnected};
@ -12,6 +12,7 @@ use {bad_response, disconnected};
pub enum Execute { pub enum Execute {
#[state_machine_future(start, transitions(ReadResponse))] #[state_machine_future(start, transitions(ReadResponse))]
Start { Start {
client: Client,
request: PendingRequest, request: PendingRequest,
statement: Statement, statement: Statement,
}, },
@ -31,7 +32,7 @@ pub enum Execute {
impl PollExecute for Execute { impl PollExecute for Execute {
fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> { fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> {
let state = state.take(); let state = state.take();
let receiver = state.request.send()?; let receiver = state.client.send(state.request)?;
// the statement can drop after this point, since its close will queue up after the execution // the statement can drop after this point, since its close will queue up after the execution
transition!(ReadResponse { receiver }) transition!(ReadResponse { receiver })
@ -82,7 +83,7 @@ impl PollExecute for Execute {
} }
impl ExecuteFuture { impl ExecuteFuture {
pub fn new(request: PendingRequest, statement: Statement) -> ExecuteFuture { pub fn new(client: Client, request: PendingRequest, statement: Statement) -> ExecuteFuture {
Execute::start(request, statement) Execute::start(client, request, statement)
} }
} }

View File

@ -8,7 +8,6 @@ use std::vec;
use error::{self, Error}; use error::{self, Error};
use proto::client::{Client, PendingRequest}; use proto::client::{Client, PendingRequest};
use proto::connection::Request;
use proto::statement::Statement; use proto::statement::Statement;
use proto::typeinfo::TypeinfoFuture; use proto::typeinfo::TypeinfoFuture;
use types::{Oid, Type}; use types::{Oid, Type};
@ -19,47 +18,41 @@ use {bad_response, disconnected};
pub enum Prepare { pub enum Prepare {
#[state_machine_future(start, transitions(ReadParseComplete))] #[state_machine_future(start, transitions(ReadParseComplete))]
Start { Start {
request: PendingRequest,
sender: mpsc::UnboundedSender<Request>,
name: String,
client: Client, client: Client,
request: PendingRequest,
name: String,
}, },
#[state_machine_future(transitions(ReadParameterDescription))] #[state_machine_future(transitions(ReadParameterDescription))]
ReadParseComplete { ReadParseComplete {
sender: mpsc::UnboundedSender<Request>, client: Client,
receiver: mpsc::Receiver<Message>, receiver: mpsc::Receiver<Message>,
name: String, name: String,
client: Client,
}, },
#[state_machine_future(transitions(ReadRowDescription))] #[state_machine_future(transitions(ReadRowDescription))]
ReadParameterDescription { ReadParameterDescription {
sender: mpsc::UnboundedSender<Request>, client: Client,
receiver: mpsc::Receiver<Message>, receiver: mpsc::Receiver<Message>,
name: String, name: String,
client: Client,
}, },
#[state_machine_future(transitions(ReadReadyForQuery))] #[state_machine_future(transitions(ReadReadyForQuery))]
ReadRowDescription { ReadRowDescription {
sender: mpsc::UnboundedSender<Request>, client: Client,
receiver: mpsc::Receiver<Message>, receiver: mpsc::Receiver<Message>,
name: String, name: String,
parameters: Vec<Oid>, parameters: Vec<Oid>,
client: Client,
}, },
#[state_machine_future(transitions(GetParameterTypes, GetColumnTypes, Finished))] #[state_machine_future(transitions(GetParameterTypes, GetColumnTypes, Finished))]
ReadReadyForQuery { ReadReadyForQuery {
sender: mpsc::UnboundedSender<Request>, client: Client,
receiver: mpsc::Receiver<Message>, receiver: mpsc::Receiver<Message>,
name: String, name: String,
parameters: Vec<Oid>, parameters: Vec<Oid>,
columns: Vec<(String, Oid)>, columns: Vec<(String, Oid)>,
client: Client,
}, },
#[state_machine_future(transitions(GetColumnTypes, Finished))] #[state_machine_future(transitions(GetColumnTypes, Finished))]
GetParameterTypes { GetParameterTypes {
future: TypeinfoFuture, future: TypeinfoFuture,
remaining_parameters: vec::IntoIter<Oid>, remaining_parameters: vec::IntoIter<Oid>,
sender: mpsc::UnboundedSender<Request>,
name: String, name: String,
parameters: Vec<Type>, parameters: Vec<Type>,
columns: Vec<(String, Oid)>, columns: Vec<(String, Oid)>,
@ -69,7 +62,6 @@ pub enum Prepare {
future: TypeinfoFuture, future: TypeinfoFuture,
cur_column_name: String, cur_column_name: String,
remaining_columns: vec::IntoIter<(String, Oid)>, remaining_columns: vec::IntoIter<(String, Oid)>,
sender: mpsc::UnboundedSender<Request>,
name: String, name: String,
parameters: Vec<Type>, parameters: Vec<Type>,
columns: Vec<Column>, columns: Vec<Column>,
@ -83,10 +75,9 @@ pub enum Prepare {
impl PollPrepare for Prepare { impl PollPrepare for Prepare {
fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> { fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> {
let state = state.take(); let state = state.take();
let receiver = state.request.send()?; let receiver = state.client.send(state.request)?;
transition!(ReadParseComplete { transition!(ReadParseComplete {
sender: state.sender,
receiver, receiver,
name: state.name, name: state.name,
client: state.client, client: state.client,
@ -101,7 +92,6 @@ impl PollPrepare for Prepare {
match message { match message {
Some(Message::ParseComplete) => transition!(ReadParameterDescription { Some(Message::ParseComplete) => transition!(ReadParameterDescription {
sender: state.sender,
receiver: state.receiver, receiver: state.receiver,
name: state.name, name: state.name,
client: state.client, client: state.client,
@ -120,7 +110,6 @@ impl PollPrepare for Prepare {
match message { match message {
Some(Message::ParameterDescription(body)) => transition!(ReadRowDescription { Some(Message::ParameterDescription(body)) => transition!(ReadRowDescription {
sender: state.sender,
receiver: state.receiver, receiver: state.receiver,
name: state.name, name: state.name,
parameters: body.parameters().collect()?, parameters: body.parameters().collect()?,
@ -148,7 +137,6 @@ impl PollPrepare for Prepare {
}; };
transition!(ReadReadyForQuery { transition!(ReadReadyForQuery {
sender: state.sender,
receiver: state.receiver, receiver: state.receiver,
name: state.name, name: state.name,
parameters: state.parameters, parameters: state.parameters,
@ -174,7 +162,6 @@ impl PollPrepare for Prepare {
transition!(GetParameterTypes { transition!(GetParameterTypes {
future: TypeinfoFuture::new(oid, state.client), future: TypeinfoFuture::new(oid, state.client),
remaining_parameters: parameters, remaining_parameters: parameters,
sender: state.sender,
name: state.name, name: state.name,
parameters: vec![], parameters: vec![],
columns: state.columns, columns: state.columns,
@ -187,7 +174,6 @@ impl PollPrepare for Prepare {
future: TypeinfoFuture::new(oid, state.client), future: TypeinfoFuture::new(oid, state.client),
cur_column_name: name, cur_column_name: name,
remaining_columns: columns, remaining_columns: columns,
sender: state.sender,
name: state.name, name: state.name,
parameters: vec![], parameters: vec![],
columns: vec![], columns: vec![],
@ -195,7 +181,7 @@ impl PollPrepare for Prepare {
} }
transition!(Finished(Statement::new( transition!(Finished(Statement::new(
state.sender, state.client.downgrade(),
state.name, state.name,
vec![], vec![],
vec![] vec![]
@ -222,7 +208,6 @@ impl PollPrepare for Prepare {
future: TypeinfoFuture::new(oid, client), future: TypeinfoFuture::new(oid, client),
cur_column_name: name, cur_column_name: name,
remaining_columns: columns, remaining_columns: columns,
sender: state.sender,
name: state.name, name: state.name,
parameters: state.parameters, parameters: state.parameters,
columns: vec![], columns: vec![],
@ -230,7 +215,7 @@ impl PollPrepare for Prepare {
} }
transition!(Finished(Statement::new( transition!(Finished(Statement::new(
state.sender, client.downgrade(),
state.name, state.name,
state.parameters, state.parameters,
vec![], vec![],
@ -240,7 +225,7 @@ impl PollPrepare for Prepare {
fn poll_get_column_types<'a>( fn poll_get_column_types<'a>(
state: &'a mut RentToOwn<'a, GetColumnTypes>, state: &'a mut RentToOwn<'a, GetColumnTypes>,
) -> Poll<AfterGetColumnTypes, Error> { ) -> Poll<AfterGetColumnTypes, Error> {
loop { let client = loop {
let (ty, client) = try_ready!(state.future.poll()); let (ty, client) = try_ready!(state.future.poll());
let name = mem::replace(&mut state.cur_column_name, String::new()); let name = mem::replace(&mut state.cur_column_name, String::new());
state.columns.push(Column::new(name, ty)); state.columns.push(Column::new(name, ty));
@ -250,13 +235,13 @@ impl PollPrepare for Prepare {
state.cur_column_name = name; state.cur_column_name = name;
state.future = TypeinfoFuture::new(oid, client); state.future = TypeinfoFuture::new(oid, client);
} }
None => break, None => break client,
} }
} };
let state = state.take(); let state = state.take();
transition!(Finished(Statement::new( transition!(Finished(Statement::new(
state.sender, client.downgrade(),
state.name, state.name,
state.parameters, state.parameters,
state.columns, state.columns,
@ -265,12 +250,7 @@ impl PollPrepare for Prepare {
} }
impl PrepareFuture { impl PrepareFuture {
pub fn new( pub fn new(client: Client, request: PendingRequest, name: String) -> PrepareFuture {
request: PendingRequest, Prepare::start(client, request, name)
sender: mpsc::UnboundedSender<Request>,
name: String,
client: Client,
) -> PrepareFuture {
Prepare::start(request, sender, name, client)
} }
} }

View File

@ -4,13 +4,14 @@ use postgres_protocol::message::backend::Message;
use std::mem; use std::mem;
use error::{self, Error}; use error::{self, Error};
use proto::client::PendingRequest; use proto::client::{Client, PendingRequest};
use proto::row::Row; use proto::row::Row;
use proto::statement::Statement; use proto::statement::Statement;
use {bad_response, disconnected}; use {bad_response, disconnected};
enum State { enum State {
Start { Start {
client: Client,
request: PendingRequest, request: PendingRequest,
statement: Statement, statement: Statement,
}, },
@ -33,8 +34,12 @@ impl Stream for QueryStream {
fn poll(&mut self) -> Poll<Option<Row>, Error> { fn poll(&mut self) -> Poll<Option<Row>, Error> {
loop { loop {
match mem::replace(&mut self.0, State::Done) { match mem::replace(&mut self.0, State::Done) {
State::Start { request, statement } => { State::Start {
let receiver = request.send()?; client,
request,
statement,
} => {
let receiver = client.send(request)?;
self.0 = State::ReadingResponse { self.0 = State::ReadingResponse {
receiver, receiver,
statement, statement,
@ -102,7 +107,11 @@ impl Stream for QueryStream {
} }
impl QueryStream { impl QueryStream {
pub fn new(request: PendingRequest, statement: Statement) -> QueryStream { pub fn new(client: Client, request: PendingRequest, statement: Statement) -> QueryStream {
QueryStream(State::Start { request, statement }) QueryStream(State::Start {
client,
request,
statement,
})
} }
} }

View File

@ -1,13 +1,11 @@
use futures::sync::mpsc;
use postgres_protocol::message::frontend;
use postgres_shared::stmt::Column; use postgres_shared::stmt::Column;
use std::sync::Arc; use std::sync::Arc;
use proto::connection::Request; use proto::client::WeakClient;
use types::Type; use types::Type;
pub struct StatementInner { pub struct StatementInner {
sender: mpsc::UnboundedSender<Request>, client: WeakClient,
name: String, name: String,
params: Vec<Type>, params: Vec<Type>,
columns: Vec<Column>, columns: Vec<Column>,
@ -15,14 +13,9 @@ pub struct StatementInner {
impl Drop for StatementInner { impl Drop for StatementInner {
fn drop(&mut self) { fn drop(&mut self) {
let mut buf = vec![]; if let Some(client) = self.client.upgrade() {
frontend::close(b'S', &self.name, &mut buf).expect("statement name not valid"); client.close_statement(&self.name);
frontend::sync(&mut buf); }
let (sender, _) = mpsc::channel(0);
let _ = self.sender.unbounded_send(Request {
messages: buf,
sender,
});
} }
} }
@ -31,13 +24,13 @@ pub struct Statement(Arc<StatementInner>);
impl Statement { impl Statement {
pub fn new( pub fn new(
sender: mpsc::UnboundedSender<Request>, client: WeakClient,
name: String, name: String,
params: Vec<Type>, params: Vec<Type>,
columns: Vec<Column>, columns: Vec<Column>,
) -> Statement { ) -> Statement {
Statement(Arc::new(StatementInner { Statement(Arc::new(StatementInner {
sender, client,
name, name,
params, params,
columns, columns,

View File

@ -31,7 +31,10 @@ WHERE t.oid = $1
#[derive(StateMachineFuture)] #[derive(StateMachineFuture)]
pub enum Typeinfo { pub enum Typeinfo {
#[state_machine_future(start, transitions(PreparingTypeinfo, QueryingTypeinfo, Finished))] #[state_machine_future(
start,
transitions(PreparingTypeinfo, QueryingTypeinfo, Finished)
)]
Start { oid: Oid, client: Client }, Start { oid: Oid, client: Client },
#[state_machine_future(transitions(PreparingTypeinfoFallback, QueryingTypeinfo))] #[state_machine_future(transitions(PreparingTypeinfoFallback, QueryingTypeinfo))]
PreparingTypeinfo { PreparingTypeinfo {
@ -47,8 +50,12 @@ pub enum Typeinfo {
}, },
#[state_machine_future( #[state_machine_future(
transitions( transitions(
CachingType, QueryingEnumVariants, QueryingDomainBasetype, QueryingArrayElem, CachingType,
QueryingCompositeFields, QueryingRangeSubtype QueryingEnumVariants,
QueryingDomainBasetype,
QueryingArrayElem,
QueryingCompositeFields,
QueryingRangeSubtype
) )
)] )]
QueryingTypeinfo { QueryingTypeinfo {
@ -101,19 +108,17 @@ pub enum Typeinfo {
impl PollTypeinfo for Typeinfo { impl PollTypeinfo for Typeinfo {
fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> { fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> {
let mut state = state.take(); let state = state.take();
if let Some(ty) = Type::from_oid(state.oid) { if let Some(ty) = Type::from_oid(state.oid) {
transition!(Finished((ty, state.client))); transition!(Finished((ty, state.client)));
} }
let ty = state.client.state.lock().types.get(&state.oid).cloned(); if let Some(ty) = state.client.cached_type(state.oid) {
if let Some(ty) = ty {
transition!(Finished((ty, state.client))); transition!(Finished((ty, state.client)));
} }
let statement = state.client.state.lock().typeinfo_query.clone(); match state.client.typeinfo_query() {
match statement {
Some(statement) => transition!(QueryingTypeinfo { Some(statement) => transition!(QueryingTypeinfo {
future: state.client.query(&statement, &[&state.oid]).collect(), future: state.client.query(&statement, &[&state.oid]).collect(),
oid: state.oid, oid: state.oid,
@ -152,10 +157,10 @@ impl PollTypeinfo for Typeinfo {
} }
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
let mut state = state.take(); let state = state.take();
let future = state.client.query(&statement, &[&state.oid]).collect(); let future = state.client.query(&statement, &[&state.oid]).collect();
state.client.state.lock().typeinfo_query = Some(statement); state.client.set_typeinfo_query(&statement);
transition!(QueryingTypeinfo { transition!(QueryingTypeinfo {
future, future,
oid: state.oid, oid: state.oid,
@ -167,10 +172,10 @@ impl PollTypeinfo for Typeinfo {
state: &'a mut RentToOwn<'a, PreparingTypeinfoFallback>, state: &'a mut RentToOwn<'a, PreparingTypeinfoFallback>,
) -> Poll<AfterPreparingTypeinfoFallback, Error> { ) -> Poll<AfterPreparingTypeinfoFallback, Error> {
let statement = try_ready!(state.future.poll()); let statement = try_ready!(state.future.poll());
let mut state = state.take(); let state = state.take();
let future = state.client.query(&statement, &[&state.oid]).collect(); let future = state.client.query(&statement, &[&state.oid]).collect();
state.client.state.lock().typeinfo_query = Some(statement); state.client.set_typeinfo_query(&statement);
transition!(QueryingTypeinfo { transition!(QueryingTypeinfo {
future, future,
oid: state.oid, oid: state.oid,
@ -320,12 +325,7 @@ impl PollTypeinfo for Typeinfo {
state: &'a mut RentToOwn<'a, CachingType>, state: &'a mut RentToOwn<'a, CachingType>,
) -> Poll<AfterCachingType, Error> { ) -> Poll<AfterCachingType, Error> {
let state = state.take(); let state = state.take();
state state.client.cache_type(&state.ty);
.client
.state
.lock()
.types
.insert(state.oid, state.ty.clone());
transition!(Finished((state.ty, state.client))) transition!(Finished((state.ty, state.client)))
} }
} }

View File

@ -26,7 +26,8 @@ ORDER BY attnum
#[derive(StateMachineFuture)] #[derive(StateMachineFuture)]
pub enum TypeinfoComposite { pub enum TypeinfoComposite {
#[state_machine_future( #[state_machine_future(
start, transitions(PreparingTypeinfoComposite, QueryingCompositeFields) start,
transitions(PreparingTypeinfoComposite, QueryingCompositeFields)
)] )]
Start { oid: Oid, client: Client }, Start { oid: Oid, client: Client },
#[state_machine_future(transitions(QueryingCompositeFields))] #[state_machine_future(transitions(QueryingCompositeFields))]
@ -55,10 +56,9 @@ pub enum TypeinfoComposite {
impl PollTypeinfoComposite for TypeinfoComposite { impl PollTypeinfoComposite for TypeinfoComposite {
fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> { fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> {
let mut state = state.take(); let state = state.take();
let statement = state.client.state.lock().typeinfo_composite_query.clone(); match state.client.typeinfo_composite_query() {
match statement {
Some(statement) => transition!(QueryingCompositeFields { Some(statement) => transition!(QueryingCompositeFields {
future: state.client.query(&statement, &[&state.oid]).collect(), future: state.client.query(&statement, &[&state.oid]).collect(),
client: state.client, client: state.client,
@ -79,9 +79,9 @@ impl PollTypeinfoComposite for TypeinfoComposite {
state: &'a mut RentToOwn<'a, PreparingTypeinfoComposite>, state: &'a mut RentToOwn<'a, PreparingTypeinfoComposite>,
) -> Poll<AfterPreparingTypeinfoComposite, Error> { ) -> Poll<AfterPreparingTypeinfoComposite, Error> {
let statement = try_ready!(state.future.poll()); let statement = try_ready!(state.future.poll());
let mut state = state.take(); let state = state.take();
state.client.state.lock().typeinfo_composite_query = Some(statement.clone()); state.client.set_typeinfo_composite_query(&statement);
transition!(QueryingCompositeFields { transition!(QueryingCompositeFields {
future: state.client.query(&statement, &[&state.oid]).collect(), future: state.client.query(&statement, &[&state.oid]).collect(),
client: state.client, client: state.client,

View File

@ -28,7 +28,10 @@ ORDER BY oid
#[derive(StateMachineFuture)] #[derive(StateMachineFuture)]
pub enum TypeinfoEnum { pub enum TypeinfoEnum {
#[state_machine_future(start, transitions(PreparingTypeinfoEnum, QueryingEnumVariants))] #[state_machine_future(
start,
transitions(PreparingTypeinfoEnum, QueryingEnumVariants)
)]
Start { oid: Oid, client: Client }, Start { oid: Oid, client: Client },
#[state_machine_future(transitions(PreparingTypeinfoEnumFallback, QueryingEnumVariants))] #[state_machine_future(transitions(PreparingTypeinfoEnumFallback, QueryingEnumVariants))]
PreparingTypeinfoEnum { PreparingTypeinfoEnum {
@ -55,10 +58,9 @@ pub enum TypeinfoEnum {
impl PollTypeinfoEnum for TypeinfoEnum { impl PollTypeinfoEnum for TypeinfoEnum {
fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> { fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll<AfterStart, Error> {
let mut state = state.take(); let state = state.take();
let statement = state.client.state.lock().typeinfo_enum_query.clone(); match state.client.typeinfo_enum_query() {
match statement {
Some(statement) => transition!(QueryingEnumVariants { Some(statement) => transition!(QueryingEnumVariants {
future: state.client.query(&statement, &[&state.oid]).collect(), future: state.client.query(&statement, &[&state.oid]).collect(),
client: state.client, client: state.client,
@ -96,9 +98,9 @@ impl PollTypeinfoEnum for TypeinfoEnum {
} }
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
let mut state = state.take(); let state = state.take();
state.client.state.lock().typeinfo_enum_query = Some(statement.clone()); state.client.set_typeinfo_enum_query(&statement);
transition!(QueryingEnumVariants { transition!(QueryingEnumVariants {
future: state.client.query(&statement, &[&state.oid]).collect(), future: state.client.query(&statement, &[&state.oid]).collect(),
client: state.client, client: state.client,
@ -109,9 +111,9 @@ impl PollTypeinfoEnum for TypeinfoEnum {
state: &'a mut RentToOwn<'a, PreparingTypeinfoEnumFallback>, state: &'a mut RentToOwn<'a, PreparingTypeinfoEnumFallback>,
) -> Poll<AfterPreparingTypeinfoEnumFallback, Error> { ) -> Poll<AfterPreparingTypeinfoEnumFallback, Error> {
let statement = try_ready!(state.future.poll()); let statement = try_ready!(state.future.poll());
let mut state = state.take(); let state = state.take();
state.client.state.lock().typeinfo_enum_query = Some(statement.clone()); state.client.set_typeinfo_enum_query(&statement);
transition!(QueryingEnumVariants { transition!(QueryingEnumVariants {
future: state.client.query(&statement, &[&state.oid]).collect(), future: state.client.query(&statement, &[&state.oid]).collect(),
client: state.client, client: state.client,

View File

@ -482,17 +482,14 @@ fn notifications() {
let listen = client.prepare("LISTEN test_notifications"); let listen = client.prepare("LISTEN test_notifications");
let listen = runtime.block_on(listen).unwrap(); let listen = runtime.block_on(listen).unwrap();
runtime.block_on(client.execute(&listen, &[])).unwrap(); runtime.block_on(client.execute(&listen, &[])).unwrap();
drop(listen); // FIXME
let notify = client.prepare("NOTIFY test_notifications, 'hello'"); let notify = client.prepare("NOTIFY test_notifications, 'hello'");
let notify = runtime.block_on(notify).unwrap(); let notify = runtime.block_on(notify).unwrap();
runtime.block_on(client.execute(&notify, &[])).unwrap(); runtime.block_on(client.execute(&notify, &[])).unwrap();
drop(notify); // FIXME
let notify = client.prepare("NOTIFY test_notifications, 'world'"); let notify = client.prepare("NOTIFY test_notifications, 'world'");
let notify = runtime.block_on(notify).unwrap(); let notify = runtime.block_on(notify).unwrap();
runtime.block_on(client.execute(&notify, &[])).unwrap(); runtime.block_on(client.execute(&notify, &[])).unwrap();
drop(notify); // FIXME
drop(client); drop(client);
runtime.run().unwrap(); runtime.run().unwrap();