浏览代码

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 9 年之前
父节点
当前提交
cd6790d4ae
共有 2 个文件被更改,包括 31 次插入0 次删除
  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 {