Fix fd-leak in rpcClient close it pro-actively.

This commit is contained in:
Harshavardhana 2016-08-28 20:04:47 -07:00
parent 0513b3ed07
commit cbe87cb2ed
3 changed files with 20 additions and 24 deletions

View File

@ -149,11 +149,14 @@ func (authClient *AuthRPCClient) Call(serviceMethod string, args interface {
args.SetToken(authClient.token) args.SetToken(authClient.token)
args.SetTimestamp(authClient.tstamp) args.SetTimestamp(authClient.tstamp)
// .. // Call the underlying rpc.
err = authClient.rpc.Call(serviceMethod, args, reply) err = authClient.rpc.Call(serviceMethod, args, reply)
// Invalidate token to mark for re-login on subsequent reconnect. // Invalidate token to mark for re-login on subsequent reconnect.
if err != nil && err == rpc.ErrShutdown { if err != nil {
authClient.isLoggedIn = false if err.Error() == rpc.ErrShutdown.Error() {
authClient.isLoggedIn = false
}
} }
} }
return err return err

View File

@ -75,7 +75,6 @@ func (rpcClient *RPCClient) dialRPCClient() (*rpc.Client, error) {
// Call makes a RPC call to the remote endpoint using the default codec, namely encoding/gob. // Call makes a RPC call to the remote endpoint using the default codec, namely encoding/gob.
func (rpcClient *RPCClient) Call(serviceMethod string, args interface{}, reply interface{}) error { func (rpcClient *RPCClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
// Make a copy below so that we can safely (continue to) work with the rpc.Client. // Make a copy below so that we can safely (continue to) work with the rpc.Client.
// Even in the case the two threads would simultaneously find that the connection is not initialised, // Even in the case the two threads would simultaneously find that the connection is not initialised,
// they would both attempt to dial and only one of them would succeed in doing so. // they would both attempt to dial and only one of them would succeed in doing so.
@ -93,15 +92,24 @@ func (rpcClient *RPCClient) Call(serviceMethod string, args interface{}, reply i
// If the RPC fails due to a network-related error, then we reset // If the RPC fails due to a network-related error, then we reset
// rpc.Client for a subsequent reconnect. // rpc.Client for a subsequent reconnect.
err := rpcLocalStack.Call(serviceMethod, args, reply) err := rpcLocalStack.Call(serviceMethod, args, reply)
if IsRPCError(err) { if err != nil {
rpcClient.clearRPCClient() if err.Error() == rpc.ErrShutdown.Error() {
// Reset rpcClient.rpc to nil to trigger a reconnect in future
// and close the underlying connection.
rpcClient.clearRPCClient()
// Close the underlying connection.
rpcLocalStack.Close()
// Set rpc error as rpc.ErrShutdown type.
err = rpc.ErrShutdown
}
} }
return err return err
} }
// Close closes the underlying socket file descriptor. // Close closes the underlying socket file descriptor.
func (rpcClient *RPCClient) Close() error { func (rpcClient *RPCClient) Close() error {
// See comment above for making a copy on local stack // See comment above for making a copy on local stack
rpcLocalStack := rpcClient.getRPCClient() rpcLocalStack := rpcClient.getRPCClient()
@ -115,18 +123,3 @@ func (rpcClient *RPCClient) Close() error {
rpcClient.clearRPCClient() rpcClient.clearRPCClient()
return rpcLocalStack.Close() return rpcLocalStack.Close()
} }
// IsRPCError returns true if the error value is due to a network related
// failure, false otherwise.
func IsRPCError(err error) bool {
if err == nil {
return false
}
// The following are net/rpc specific errors that indicate that
// the connection may have been reset. Reset rpcClient.rpc to nil
// to trigger a reconnect in future.
if err == rpc.ErrShutdown {
return true
}
return false
}

View File

@ -48,9 +48,9 @@ var serverCmd = cli.Command{
minio {{.Name}} - {{.Usage}} minio {{.Name}} - {{.Usage}}
USAGE: USAGE:
minio {{.Name}} [OPTIONS] PATH [PATH...] minio {{.Name}} [FLAGS] PATH [PATH...]
OPTIONS: FLAGS:
{{range .Flags}}{{.}} {{range .Flags}}{{.}}
{{end}} {{end}}
ENVIRONMENT VARIABLES: ENVIRONMENT VARIABLES: