66package graceful
77
88import (
9- "container/list"
109 "crypto/tls"
1110 "net"
1211 "os"
@@ -34,11 +33,9 @@ type Server struct {
3433 address string
3534 listener net.Listener
3635
37- lock sync.RWMutex
38- state state
39- // FIXME: actually we do not need to record the whole list, just a counter should be enough
40- // Because the connections will be closed by OS, no need to track them one by one.
41- connList * list.List
36+ lock sync.RWMutex
37+ state state
38+ connCounter int64
4239 connEmptyCond * sync.Cond
4340
4441 BeforeBegin func (network , address string )
@@ -56,7 +53,6 @@ func NewServer(network, address, name string) *Server {
5653 }
5754 srv := & Server {
5855 state : stateInit ,
59- connList : list .New (),
6056 network : network ,
6157 address : address ,
6258 PerWriteTimeout : setting .PerWriteTimeout ,
@@ -185,7 +181,7 @@ func (srv *Server) setState(st state) {
185181
186182func (srv * Server ) waitForActiveConnections () {
187183 srv .lock .Lock ()
188- for srv .connList . Len () > 0 {
184+ for srv .connCounter > 0 {
189185 srv .connEmptyCond .Wait ()
190186 }
191187 srv .lock .Unlock ()
@@ -200,42 +196,28 @@ func (srv *Server) wrapConnection(c net.Conn) (net.Conn, error) {
200196 return nil , syscall .EINVAL // same as AcceptTCP
201197 }
202198
203- wc := & wrappedConn {Conn : c , server : srv }
204- wc .listElem = srv .connList .PushBack (wc )
205- return wc , nil
199+ srv .connCounter ++
200+ return & wrappedConn {Conn : c , server : srv }, nil
206201}
207202
208- func (srv * Server ) removeConnection (conn * wrappedConn ) {
203+ func (srv * Server ) removeConnection (_ * wrappedConn ) {
209204 srv .lock .Lock ()
210205 defer srv .lock .Unlock ()
211206
212- if conn .listElem == nil {
213- return
214- }
215- srv .connList .Remove (conn .listElem )
216- if srv .connList .Len () == 0 {
207+ srv .connCounter --
208+ if srv .connCounter <= 0 {
217209 srv .connEmptyCond .Broadcast ()
218210 }
219211}
220212
221213// closeAllConnections forcefully closes all active connections
222214func (srv * Server ) closeAllConnections () {
223215 srv .lock .Lock ()
224- if srv .connList .Len () > 0 {
225- log .Warn ("Forcefully closing all %d connections" , srv .connList .Len ())
226- }
227- conns := make ([]* wrappedConn , 0 , srv .connList .Len ())
228- for e := srv .connList .Front (); e != nil ; e = e .Next () {
229- conn := e .Value .(* wrappedConn )
230- conn .listElem = nil // mark as removed, will close it later to avoid deadlock of "server.lock"
231- conns = append (conns , conn )
216+ if srv .connCounter > 0 {
217+ log .Warn ("After graceful shutdown period, %d connections are still active. Forcefully close." , srv .connCounter )
218+ srv .connCounter = 0 // OS will close all the connections after the process exits, so we just assume there is no active connection now
232219 }
233- srv .connList = list .New ()
234220 srv .lock .Unlock ()
235-
236- for _ , conn := range conns {
237- _ = conn .Close () // do real close outside of lock
238- }
239221 srv .connEmptyCond .Broadcast ()
240222}
241223
@@ -262,7 +244,7 @@ func newWrappedListener(l net.Listener, srv *Server) *wrappedListener {
262244
263245func (wl * wrappedListener ) Accept () (c net.Conn , err error ) {
264246 if tcl , ok := wl .Listener .(* net.TCPListener ); ok {
265- // Set keepalive on TCPListeners connections if possible, http.tcpKeepAliveListener
247+ // Set keepalive on TCPListeners connections if possible, see http.tcpKeepAliveListener
266248 tc , err := tcl .AcceptTCP ()
267249 if err != nil {
268250 return nil , err
@@ -287,11 +269,6 @@ func (wl *wrappedListener) File() (*os.File, error) {
287269
288270type wrappedConn struct {
289271 net.Conn
290-
291- // listElem is protected by the server's lock (used by the server to remove conn itself from the list)
292- // nil means it has been removed
293- listElem * list.Element
294-
295272 server * Server
296273 deadline time.Time
297274}
0 commit comments