github.com/Cloud-Foundations/Dominator@v0.3.4/lib/connpool/api.go (about) 1 /* 2 Package connpool provides for managing network connections with a resource 3 pool. 4 5 Package connpool may be used to create and free network connections. 6 The number of concurrent network connections that may be open is limited to 7 fit within the underlying file descriptor limit. Connections may be placed 8 on an internal freelist for later re-use, potentially eliminating connection 9 setup overhead for frequently re-opened connections. 10 11 An application will typically call New once for each network address it 12 expects to later connect to. When the application wants to connect it calls 13 the Get method and calls the Put method to release the connection. 14 A typical programming pattern is: 15 cr0 := New(...) 16 cr1 := New(...) 17 go func() { 18 for ... { 19 c := cr0.Get(...) 20 defer c.Put() 21 if err { c.Close() } 22 } 23 }() 24 go func() { 25 for ... { 26 c := cr1.Get(...) 27 defer c.Put() 28 if err { c.Close() } 29 } 30 }() 31 This pattern ensures Get and Put are always matched, and if there is a 32 communications error, Close shuts down the connection so that a subsequent 33 Get creates a new underlying connection. 34 35 It is resonable to create one goroutine for each resource, since the Get 36 methods will block, waiting for available resources. 37 */ 38 package connpool 39 40 import ( 41 "net" 42 "time" 43 44 "github.com/Cloud-Foundations/Dominator/lib/resourcepool" 45 ) 46 47 // Dialer implements a dialer that can be use to create connections. 48 type Dialer interface { 49 Dial(network, address string) (net.Conn, error) 50 } 51 52 // GetResourcePool returns a global resourcepool.Pool which may be used by other 53 // packages which need to share a common resource pool with the connpool 54 // package. This is needed for efficient sharing of the underlying file 55 // descriptors (connection slots). 56 func GetResourcePool() *resourcepool.Pool { 57 return getResourcePool() 58 } 59 60 type privateConnResource struct { 61 connResource *ConnResource 62 dialer Dialer 63 } 64 65 // ConnResource manages a single Conn. 66 type ConnResource struct { 67 network string 68 address string 69 resource *resourcepool.Resource 70 privateConnResource privateConnResource 71 conn *Conn 72 netConn net.Conn 73 } 74 75 // New returns a ConnResource for the specified network address. It may be used 76 // later to obtain a Conn network connection which is part of a managed pool of 77 // connection slots (to limit consumption of resources such as file 78 // descriptors). Connections can be released with the Put method but the 79 // underlying connection may be kept open for later re-use. The Conn is placed 80 // on an internal list. 81 func New(network, address string) *ConnResource { 82 return newConnResource(network, address) 83 } 84 85 // Get will return a Conn network connection. It implements the net.Conn 86 // interface from the standard library. Get will wait until a resource is 87 // available or a message is received on cancelChannel. If cancelChannel is nil 88 // then Get will wait indefinitely until a resource is available. If the wait is 89 // cancelled then Get will return ErrorResourceLimitExceeded. The timeout 90 // specifies how long to wait (after a resource is available) to make the 91 // connection. If timeout is zero or less, the underlying OS timeout is used 92 // (typically 3 minutes for TCP). 93 // Get will panic if it is called again without an intervening Close or Put. 94 func (cr *ConnResource) Get(cancelChannel <-chan struct{}, 95 timeout time.Duration) (*Conn, error) { 96 return cr.get(cancelChannel, &net.Dialer{Timeout: timeout}) 97 } 98 99 // GetWithDialer will return a Conn network connection which implements the 100 // net.Conn interface from the standard library. GetWithDialer will wait until 101 // a resource is available or a message is received on cancelChannel. If 102 // cancelChannel is nil then GetWithDialer will wait indefinitely until a 103 // resource is available. If the wait is cancelled then GetWithDialer will 104 // return ErrorResourceLimitExceeded. 105 // The dialer is used to perform the operation which creates the connection. A 106 // *net.Dialer type from the standard library satisfies the Dialer interface, 107 // and may be used to specify how long to wait (after a resource is available) 108 // to make the connection. The OS may impose it's own timeout (typically 3 109 // minutes for TCP). A different dialer may be used to create TLS connections. 110 // Note that changing dialer types does not guarantee the connection type 111 // returned, as the dialer may not be called on every call to GetWithDialer, 112 // thus changing dialer types will result in unpredictable behaviour. 113 // GetWithDialer will panic if it is called again without an intervening Close 114 // or Put. 115 func (cr *ConnResource) GetWithDialer(cancelChannel <-chan struct{}, 116 dialer Dialer) (*Conn, error) { 117 return cr.get(cancelChannel, dialer) 118 } 119 120 // ScheduleClose will immediately Close the associated Conn if it is not in use 121 // or will mark the Conn to be closed when it is next Put. 122 func (cr *ConnResource) ScheduleClose() { 123 cr.resource.ScheduleRelease() 124 } 125 126 // Conn is a managed network connection. It implements the net.Conn interface 127 // from the standard library. 128 type Conn struct { 129 net.Conn 130 resource *ConnResource 131 } 132 133 // Close will close the connection, immediately freeing the underlying resource. 134 // It may no longer be used for communication. 135 func (conn *Conn) Close() error { 136 return conn.close() 137 } 138 139 // Put will release the connection. It may no longer be used for communication. 140 // It may be internally closed later if required to free limited resources (such 141 // as file descriptors). If Put is called after Close, no action is taken (this 142 // is a safe operation and is commonly used in some programming patterns). 143 func (conn *Conn) Put() { 144 conn.put() 145 }