@@ -199,7 +199,7 @@ func (bp *BackedPipe) Close() error {
199
199
func (bp * BackedPipe ) Connected () bool {
200
200
bp .mu .RLock ()
201
201
defer bp .mu .RUnlock ()
202
- return bp .state == connected
202
+ return bp .state == connected && bp . reader . Connected () && bp . writer . Connected ()
203
203
}
204
204
205
205
// reconnectLocked handles the reconnection logic. Must be called with write lock held.
@@ -223,47 +223,40 @@ func (bp *BackedPipe) reconnectLocked() error {
223
223
bp .conn = nil
224
224
}
225
225
226
- // Gather local sequence numbers:
227
- // - readerSeqNum: how many bytes we've successfully read from remote (send to remote)
228
- // - writerSeqNum: how many bytes we've written so far (used for validation)
229
- readerSeqNum := bp .reader .SequenceNum ()
230
- writerSeqNum := bp .writer .SequenceNum ()
231
-
232
226
// Increment the generation and update both reader and writer.
233
227
// We do it now to track even the connections that fail during
234
228
// Reconnect.
235
229
bp .connGen ++
236
230
bp .reader .SetGeneration (bp .connGen )
237
231
bp .writer .SetGeneration (bp .connGen )
238
232
239
- // Send our reader sequence number to the remote and receive its reader sequence
240
- // number. We will replay our outbound data from that point and backed pipe on the other
241
- // side will replay from our reader sequence number.
242
- conn , remoteReaderSeqNum , err := bp .reconnector .Reconnect (bp .ctx , readerSeqNum )
243
- if err != nil {
244
- return ErrReconnectFailed
245
- }
246
-
247
- // Validate sequence numbers
248
- if remoteReaderSeqNum > writerSeqNum {
249
- _ = conn .Close ()
250
- return ErrInvalidSequenceNumber
251
- }
252
-
253
233
// Reconnect reader and writer
254
234
seqNum := make (chan uint64 , 1 )
255
235
newR := make (chan io.Reader , 1 )
256
236
257
237
go bp .reader .Reconnect (seqNum , newR )
258
238
259
- // Get sequence number and send new reader
260
- <- seqNum
239
+ // Get the precise reader sequence number from the reader while it holds its lock
240
+ readerSeqNum , ok := <- seqNum
241
+ if ! ok {
242
+ // Reader was closed during reconnection
243
+ return ErrReconnectFailed
244
+ }
245
+
246
+ // Perform reconnect using the exact sequence number we just received
247
+ conn , remoteReaderSeqNum , err := bp .reconnector .Reconnect (bp .ctx , readerSeqNum )
248
+ if err != nil {
249
+ // Unblock reader reconnect
250
+ newR <- nil
251
+ return ErrReconnectFailed
252
+ }
253
+
254
+ // Provide the new connection to the reader (reader still holds its lock)
261
255
newR <- conn
262
256
263
257
// Replay our outbound data from the remote's reader sequence number
264
- err = bp .writer .Reconnect (remoteReaderSeqNum , conn )
265
- if err != nil {
266
- _ = conn .Close ()
258
+ writerReconnectErr := bp .writer .Reconnect (remoteReaderSeqNum , conn )
259
+ if writerReconnectErr != nil {
267
260
return ErrReconnectWriterFailed
268
261
}
269
262
0 commit comments