Replace mutex in client.do() with a channel to avoid deadlock and introduce command timeout

This commit is contained in:
Endre Hirling 2015-07-06 21:40:49 +02:00
parent df1af4f8cb
commit c615e74af8

View File

@ -6,6 +6,7 @@ import (
"bufio" "bufio"
"net" "net"
"sync" "sync"
"time"
) )
// One client connect to one server. // One client connect to one server.
@ -20,6 +21,8 @@ type Client struct {
conn net.Conn conn net.Conn
rw *bufio.ReadWriter rw *bufio.ReadWriter
RespTimeout time.Duration // response timeout for do() in ms
ErrorHandler ErrorHandler ErrorHandler ErrorHandler
} }
@ -31,6 +34,7 @@ func New(network, addr string) (client *Client, err error) {
respHandler: make(map[string]ResponseHandler, queueSize), respHandler: make(map[string]ResponseHandler, queueSize),
innerHandler: make(map[string]ResponseHandler, queueSize), innerHandler: make(map[string]ResponseHandler, queueSize),
in: make(chan *Response, queueSize), in: make(chan *Response, queueSize),
RespTimeout: 1000,
} }
client.conn, err = net.Dial(client.net, client.addr) client.conn, err = net.Dial(client.net, client.addr)
if err != nil { if err != nil {
@ -175,21 +179,26 @@ func (client *Client) handleInner(key string, resp *Response) *Response {
return resp return resp
} }
type handleOrError struct {
handle string
err error
}
func (client *Client) do(funcname string, data []byte, func (client *Client) do(funcname string, data []byte,
flag uint32) (handle string, err error) { flag uint32) (handle string, err error) {
if client.conn == nil { if client.conn == nil {
return "", ErrLostConn return "", ErrLostConn
} }
var mutex sync.Mutex var result = make(chan handleOrError, 1)
mutex.Lock()
client.lastcall = "c" client.lastcall = "c"
client.innerHandler["c"] = func(resp *Response) { client.innerHandler["c"] = func(resp *Response) {
defer mutex.Unlock()
if resp.DataType == dtError { if resp.DataType == dtError {
err = getError(resp.Data) err = getError(resp.Data)
result <- handleOrError{"", err}
return return
} }
handle = resp.Handle handle = resp.Handle
result <- handleOrError{handle, nil}
} }
id := IdGen.Id() id := IdGen.Id()
req := getJob(id, []byte(funcname), data) req := getJob(id, []byte(funcname), data)
@ -199,7 +208,15 @@ func (client *Client) do(funcname string, data []byte,
client.lastcall = "" client.lastcall = ""
return return
} }
mutex.Lock() var timer = time.After(client.RespTimeout * time.Millisecond)
select {
case ret := <-result:
return ret.handle, ret.err
case <-timer:
delete(client.innerHandler, "c")
client.lastcall = ""
return "", ErrLostConn
}
return return
} }