2021-05-08 16:36:00 +00:00
|
|
|
package ingestserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
2023-11-14 00:00:42 +00:00
|
|
|
"sort"
|
2021-05-08 16:36:00 +00:00
|
|
|
"sync"
|
2023-11-14 00:00:42 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
2021-05-08 16:36:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ConnsMap is used for tracking active connections.
|
|
|
|
type ConnsMap struct {
|
2023-11-14 00:00:42 +00:00
|
|
|
clientName string
|
|
|
|
|
2021-05-08 16:36:00 +00:00
|
|
|
mu sync.Mutex
|
|
|
|
m map[net.Conn]struct{}
|
|
|
|
isClosed bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init initializes cm.
|
2023-11-14 00:00:42 +00:00
|
|
|
func (cm *ConnsMap) Init(clientName string) {
|
|
|
|
cm.clientName = clientName
|
2021-05-08 16:36:00 +00:00
|
|
|
cm.m = make(map[net.Conn]struct{})
|
|
|
|
cm.isClosed = false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add adds c to cm.
|
|
|
|
func (cm *ConnsMap) Add(c net.Conn) bool {
|
|
|
|
cm.mu.Lock()
|
|
|
|
ok := !cm.isClosed
|
|
|
|
if ok {
|
|
|
|
cm.m[c] = struct{}{}
|
|
|
|
}
|
|
|
|
cm.mu.Unlock()
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete deletes c from cm.
|
|
|
|
func (cm *ConnsMap) Delete(c net.Conn) {
|
|
|
|
cm.mu.Lock()
|
|
|
|
delete(cm.m, c)
|
|
|
|
cm.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
2023-11-14 00:00:42 +00:00
|
|
|
// CloseAll gradually closes all the cm conns with during the given shutdownDuration.
|
2024-06-17 10:13:18 +00:00
|
|
|
//
|
|
|
|
// If shutdownDuration <= 0, then all the connections are closed simultaneously.
|
2023-11-14 00:00:42 +00:00
|
|
|
func (cm *ConnsMap) CloseAll(shutdownDuration time.Duration) {
|
2021-05-08 16:36:00 +00:00
|
|
|
cm.mu.Lock()
|
2023-11-14 02:25:10 +00:00
|
|
|
conns := make([]net.Conn, 0, len(cm.m))
|
2021-05-08 16:36:00 +00:00
|
|
|
for c := range cm.m {
|
2023-11-14 00:00:42 +00:00
|
|
|
conns = append(conns, c)
|
|
|
|
delete(cm.m, c)
|
2021-05-08 16:36:00 +00:00
|
|
|
}
|
|
|
|
cm.isClosed = true
|
|
|
|
cm.mu.Unlock()
|
2023-11-14 00:00:42 +00:00
|
|
|
|
|
|
|
if shutdownDuration <= 0 {
|
|
|
|
// Close all the connections at once.
|
|
|
|
for _, c := range conns {
|
|
|
|
_ = c.Close()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(conns) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(conns) == 1 {
|
|
|
|
// Simple case - just close a single connection and that's it!
|
|
|
|
_ = conns[0].Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-17 10:13:18 +00:00
|
|
|
// Sort conns in order to make the order of closing connections deterministic across clients.
|
|
|
|
// This should reduce resource usage spikes at clients during rolling restarts.
|
2023-11-14 00:00:42 +00:00
|
|
|
sort.Slice(conns, func(i, j int) bool {
|
|
|
|
return conns[i].RemoteAddr().String() < conns[j].RemoteAddr().String()
|
|
|
|
})
|
|
|
|
|
|
|
|
shutdownInterval := shutdownDuration / time.Duration(len(conns)-1)
|
|
|
|
startTime := time.Now()
|
|
|
|
logger.Infof("closing %d %s connections with %dms interval between them", len(conns), cm.clientName, shutdownInterval.Milliseconds())
|
|
|
|
remoteAddr := conns[0].RemoteAddr().String()
|
|
|
|
_ = conns[0].Close()
|
|
|
|
logger.Infof("closed %s connection %s", cm.clientName, remoteAddr)
|
2023-11-14 20:52:20 +00:00
|
|
|
for _, c := range conns[1:] {
|
2023-11-14 00:00:42 +00:00
|
|
|
time.Sleep(shutdownInterval)
|
|
|
|
remoteAddr := c.RemoteAddr().String()
|
|
|
|
_ = c.Close()
|
|
|
|
logger.Infof("closed %s connection %s", cm.clientName, remoteAddr)
|
|
|
|
}
|
|
|
|
logger.Infof("closed %d %s connections in %s", len(conns), cm.clientName, time.Since(startTime))
|
2021-05-08 16:36:00 +00:00
|
|
|
}
|