1212async fn Driver ::run(self : Driver , group : @async.TaskGroup [Unit ]) -> Unit {
1313 let mut active : Request? = None
1414 let mut cleaned_up = false
15+ // The reader must survive the transition between idle time and a request.
16+ // Cancelling an in-progress frame read there would lose protocol alignment.
17+ let incoming : @async.Queue [@backend.Message ] = Queue (kind=Blocking (1))
18+ let reading_request = @ref.new(false )
1519 fn cleanup(error : Error? ) {
1620 if cleaned_up {
1721 return
@@ -43,6 +47,15 @@ async fn Driver::run(self : Driver, group : @async.TaskGroup[Unit]) -> Unit {
4347 self.shared.control.close()
4448 }
4549 }
50+ let reader = group.spawn(no_wait=true , allow_failure=true , () => {
51+ self.receive_messages(incoming, reading_request)
52+ })
53+ defer @async.protect_from_cancel(() => {
54+ reader.cancel()
55+ reader.wait() catch {
56+ _ => ()
57+ }
58+ })
4659 try {
4760 while true {
4861 let request = self.shared.requests.get()
@@ -55,8 +68,9 @@ async fn Driver::run(self : Driver, group : @async.TaskGroup[Unit]) -> Unit {
5568 return
5669 }
5770 Messages | CopyIn => {
71+ reading_request.val = true
5872 self.stream.write(request.bytes)
59- self.drain_request(request, group)
73+ self.drain_request(request, incoming, group)
6074 self.close_request(request, None )
6175 active = None
6276 }
@@ -67,6 +81,48 @@ async fn Driver::run(self : Driver, group : @async.TaskGroup[Unit]) -> Unit {
6781 }
6882}
6983
84+ ///|
85+ /// Keep one owner of socket reads even when no request is in flight.
86+ async fn Driver ::receive_messages(
87+ self : Driver ,
88+ incoming : @async.Queue [@backend.Message ],
89+ reading_request : @ref.Ref [Bool ],
90+ ) -> Unit {
91+ let mut failure : Error? = None
92+ try {
93+ while true {
94+ let message = self.read_message()
95+ if self.handle_async_message(message) {
96+ continue
97+ }
98+ if !reading_request.val {
99+ match message {
100+ ErrorResponse (body) =>
101+ raise ClientError ::Database (parse_database_error(body.fields()))
102+ _ =>
103+ raise ClientError ::UnexpectedMessage (
104+ "backend response without an active request",
105+ )
106+ }
107+ }
108+ if message is ReadyForQuery (_) {
109+ reading_request.val = false
110+ }
111+ incoming.put(message)
112+ }
113+ } catch {
114+ error => failure = Some (error)
115+ }
116+ match failure {
117+ Some (error) => {
118+ // Preserve queued requests for Driver::cleanup to close their own queues.
119+ incoming.close(error~, clear=true )
120+ self.shared.requests.close(error~)
121+ }
122+ None => ()
123+ }
124+ }
125+
70126///|
71127/// Receive the next asynchronous message buffered by the private driver.
72128///
@@ -83,17 +139,15 @@ pub async fn Client::next_message(self : Client) -> AsyncMessage? {
83139async fn Driver ::drain_request(
84140 self : Driver ,
85141 request : Request ,
142+ incoming : @async.Queue [@backend.Message ],
86143 group : @async.TaskGroup [Unit ],
87144) -> Unit {
88145 if request.kind is CopyIn {
89- self.drain_copy_in_request(request, group)
146+ self.drain_copy_in_request(request, incoming, group)
90147 return
91148 }
92149 while true {
93- let message = self.read_message()
94- if self.handle_async_message(message) {
95- continue
96- }
150+ let message = incoming.get()
97151 match request.kind {
98152 Messages => self.forward_message_to_request(request, message)
99153 CopyIn => abort("COPY IN requests use drain_copy_in_request")
@@ -131,17 +185,15 @@ async fn Driver::forward_message_to_request(
131185async fn Driver ::drain_copy_in_request(
132186 self : Driver ,
133187 request : Request ,
188+ incoming : @async.Queue [@backend.Message ],
134189 group : @async.TaskGroup [Unit ],
135190) -> Unit {
136191 let copy_input = request.copy_input.unwrap()
137192 let copy_error = request.copy_error.unwrap()
138193 let writer_stopped = @ref.new(false )
139194 let mut writer : @async.Task [Unit ]? = None
140195 while true {
141- let message = self.read_message()
142- if self.handle_async_message(message) {
143- continue
144- }
196+ let message = incoming.get()
145197 match message {
146198 CopyInResponse (_) => {
147199 guard writer is None else {
0 commit comments