Browse Source

conn: close call timeout on write error

If we get an error when writing a frame, ensure that the select in
closeWithError is not blocked indefinatly, do this by closing the calls
timeout channel before we call closeWithError.
Chris Bannister 10 năm trước cách đây
mục cha
commit
cd6790d4ae
2 tập tin đã thay đổi với 31 bổ sung0 xóa
  1. 4 0
      conn.go
  2. 27 0
      conn_test.go

+ 4 - 0
conn.go

@@ -537,6 +537,10 @@ func (c *Conn) exec(req frameWriter, tracer Tracer) (*framer, error) {
 
 	err := req.writeFrame(framer, stream)
 	if err != nil {
+		// closeWithError will block waiting for this stream to either receive a response
+		// or for us to timeout, close the timeout chan here. Im not entirely sure
+		// but we should not get a response after an error on the write side.
+		close(call.timeout)
 		// I think this is the correct thing to do, im not entirely sure. It is not
 		// ideal as readers might still get some data, but they probably wont.
 		// Here we need to be careful as the stream is not available and if all

+ 27 - 0
conn_test.go

@@ -497,6 +497,33 @@ func TestStream0(t *testing.T) {
 	}
 }
 
+func TestConnClosedBlocked(t *testing.T) {
+	// issue 664
+	const proto = 3
+
+	srv := NewTestServer(t, proto)
+	defer srv.Stop()
+	errorHandler := connErrorHandlerFn(func(conn *Conn, err error, closed bool) {
+		t.Log(err)
+	})
+
+	host := &HostInfo{peer: srv.Address}
+	conn, err := Connect(host, srv.Address, &ConnConfig{ProtoVersion: int(srv.protocol)}, errorHandler, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := conn.conn.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// This will block indefintaly if #664 is not fixed
+	err = conn.executeQuery(&Query{stmt: "void"}).Close()
+	if !strings.HasSuffix(err.Error(), "use of closed network connection") {
+		t.Fatalf("expected to get use of closed networking connection error got: %v\n", err)
+	}
+}
+
 func NewTestServer(t testing.TB, protocol uint8) *TestServer {
 	laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
 	if err != nil {