github.com/Cloud-Foundations/Dominator@v0.3.4/lib/rpcclientpool/api.go (about) 1 /* 2 Package rpcclientpool wraps net/rpc.Client to manage shared resource pools. 3 4 Package rpcclientpool wraps net/rpc.Client from the standard library so that 5 limited resources (file descriptors used for network connections) may be 6 shared easily with other packages such as lib/connpool and lib/srpc. 7 A typical programming pattern is: 8 cr0 := New(...) 9 cr1 := New(...) 10 go func() { 11 for ... { 12 c := cr0.Get(...) 13 defer c.Put() 14 if err { c.Close() } 15 } 16 }() 17 go func() { 18 for ... { 19 c := cr1.Get(...) 20 defer c.Put() 21 if err { c.Close() } 22 } 23 }() 24 This pattern ensures Get and Put are always matched, and if there is a 25 communications error, Close shuts down the connection so that a subsequent 26 Get creates a new underlying connection. 27 28 It is resonable to create one goroutine for each resource, since the Get 29 methods will block, waiting for available resources. 30 */ 31 package rpcclientpool 32 33 import ( 34 "net/rpc" 35 36 "github.com/Cloud-Foundations/Dominator/lib/net" 37 "github.com/Cloud-Foundations/Dominator/lib/resourcepool" 38 ) 39 40 // Client is a managed RPC client. It implements similar methods as rpc.Client 41 // from the standard library. 42 type Client struct { 43 rpcClient *rpc.Client 44 resource *ClientResource 45 } 46 47 func (client *Client) Call(serviceMethod string, args interface{}, 48 reply interface{}) error { 49 return client.rpcClient.Call(serviceMethod, args, reply) 50 } 51 52 // Close will close the client, immediately freeing the underlying resource. 53 // It may no longer be used for communication. 54 func (client *Client) Close() error { 55 return client.close() 56 } 57 58 func (client *Client) Go(serviceMethod string, args interface{}, 59 reply interface{}, done chan *rpc.Call) *rpc.Call { 60 return client.rpcClient.Go(serviceMethod, args, reply, done) 61 } 62 63 // Put will release the client. It may no longer be used for communication. 64 // It may be internally closed later if required to free limited resources (such 65 // as file descriptors). If Put is called after Close, no action is taken (this 66 // is a safe operation and is commonly used in some programming patterns). 67 func (client *Client) Put() { 68 client.put() 69 } 70 71 type privateClientResource struct { 72 clientResource *ClientResource 73 } 74 75 type ClientResource struct { 76 network string 77 address string 78 http bool 79 path string 80 dialer net.Dialer 81 resource *resourcepool.Resource 82 privateClientResource privateClientResource 83 client *Client 84 rpcClient *rpc.Client 85 } 86 87 // New returns a ClientResource for the specified network address. If a RPC over 88 // HTTP connection is required then http should be true and the HTTP path should 89 // be given by path. If path is empty then the default path 90 // (net/rpc.DefaultRPCPath) is used. In general, the default path should be used. 91 // The ClientResource may be used later to obtain a Client which is part of a 92 // managed pool of connection slots (to limit consumption of resources such as 93 // file descriptors). Clients can be released with the Put method but the 94 // underlying connection may be kept open for later re-use. The Client is placed 95 // on an internal list. 96 func New(network, address string, http bool, path string) *ClientResource { 97 return newClientResource(network, address, http, path, defaultDialer) 98 } 99 100 // NewWithDialer works just like New but allows this resource to use a custom 101 // dialer. 102 func NewWithDialer( 103 network, 104 address string, 105 http bool, 106 path string, 107 dialer net.Dialer) *ClientResource { 108 return newClientResource(network, address, http, path, dialer) 109 } 110 111 // Get will return a Client. Get will wait until a resource is available or a 112 // message is received on cancelChannel. If cancelChannel is nil then Get will 113 // wait indefinitely until a resource is available. If the wait is cancelled 114 // then Get will return ErrorResourceLimitExceeded. 115 // Get will panic if it is called again without an intervening Close or Put. 116 func (cr *ClientResource) Get(cancelChannel <-chan struct{}) (*Client, error) { 117 return cr.get(cancelChannel) 118 }