aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2011-10-18 15:52:49 -0700
committerRob Pike <r@golang.org>2011-10-18 15:52:49 -0700
commit4c56c30b78199c3313c1ee0042f0adcc685bae33 (patch)
treee39dce6c031e10bd704fd6236f299c32e30ea1ba
parentfc3ce34903d5f86f398eda87ca6e334f483df604 (diff)
downloadgo-4c56c30b78199c3313c1ee0042f0adcc685bae33.tar.gz
go-4c56c30b78199c3313c1ee0042f0adcc685bae33.zip
rpc: don't panic on write error.
The mechanism to record the error in the call is already in place. Fixes #2382. R=golang-dev, dsymonds, bradfitz, r CC=golang-dev https://golang.org/cl/5307043
-rw-r--r--src/pkg/rpc/client.go23
-rw-r--r--src/pkg/rpc/server_test.go26
2 files changed, 38 insertions, 11 deletions
diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go
index c77901c6dc..3dc6df1c4b 100644
--- a/src/pkg/rpc/client.go
+++ b/src/pkg/rpc/client.go
@@ -85,7 +85,8 @@ func (client *Client) send(c *Call) {
client.request.Seq = c.seq
client.request.ServiceMethod = c.ServiceMethod
if err := client.codec.WriteRequest(&client.request, c.Args); err != nil {
- panic("rpc: client encode error: " + err.String())
+ c.Error = err
+ c.done()
}
}
@@ -251,10 +252,10 @@ func (client *Client) Close() os.Error {
// the same Call object. If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
- c := new(Call)
- c.ServiceMethod = serviceMethod
- c.Args = args
- c.Reply = reply
+ call := new(Call)
+ call.ServiceMethod = serviceMethod
+ call.Args = args
+ call.Reply = reply
if done == nil {
done = make(chan *Call, 10) // buffered.
} else {
@@ -266,14 +267,14 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
log.Panic("rpc: done channel is unbuffered")
}
}
- c.Done = done
+ call.Done = done
if client.shutdown {
- c.Error = ErrShutdown
- c.done()
- return c
+ call.Error = ErrShutdown
+ call.done()
+ return call
}
- client.send(c)
- return c
+ client.send(call)
+ return call
}
// Call invokes the named function, waits for it to complete, and returns its error status.
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go
index cb2db2a65d..029741b28b 100644
--- a/src/pkg/rpc/server_test.go
+++ b/src/pkg/rpc/server_test.go
@@ -467,6 +467,32 @@ func TestCountMallocsOverHTTP(t *testing.T) {
fmt.Printf("mallocs per HTTP rpc round trip: %d\n", countMallocs(dialHTTP, t))
}
+type writeCrasher struct{}
+
+func (writeCrasher) Close() os.Error {
+ return nil
+}
+
+func (writeCrasher) Read(p []byte) (int, os.Error) {
+ return 0, os.EOF
+}
+
+func (writeCrasher) Write(p []byte) (int, os.Error) {
+ return 0, os.NewError("fake write failure")
+}
+
+func TestClientWriteError(t *testing.T) {
+ c := NewClient(writeCrasher{})
+ res := false
+ err := c.Call("foo", 1, &res)
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if err.String() != "fake write failure" {
+ t.Error("unexpected value of error:", err)
+ }
+}
+
func benchmarkEndToEnd(dial func() (*Client, os.Error), b *testing.B) {
b.StopTimer()
once.Do(startServer)