mirror of
https://github.com/gusaul/grpcox.git
synced 2024-12-27 03:10:42 +00:00
144 lines
2.5 KiB
Go
144 lines
2.5 KiB
Go
|
package core
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// ConnStore - connection store instance
|
||
|
type ConnStore struct {
|
||
|
sync.RWMutex
|
||
|
|
||
|
conn map[string]*connection
|
||
|
|
||
|
// flag for auto garbage collector(close and cleanup expired connection)
|
||
|
activeGC bool
|
||
|
// controls gc intervals
|
||
|
gcTicker *time.Ticker
|
||
|
// gc stop signal
|
||
|
done chan struct{}
|
||
|
}
|
||
|
|
||
|
type connection struct {
|
||
|
// hold connection object
|
||
|
resource *Resource
|
||
|
// keep connect
|
||
|
keepAlive bool
|
||
|
// will automatically close connection
|
||
|
expired time.Time
|
||
|
}
|
||
|
|
||
|
// NewConnectionStore - constructor connection store
|
||
|
func NewConnectionStore() *ConnStore {
|
||
|
return &ConnStore{
|
||
|
conn: make(map[string]*connection),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// StartGC - start gc ticker
|
||
|
func (c *ConnStore) StartGC(interval time.Duration) {
|
||
|
if interval <= 0 {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
c.activeGC = true
|
||
|
|
||
|
ticker := time.NewTicker(interval)
|
||
|
done := make(chan struct{})
|
||
|
|
||
|
c.Lock()
|
||
|
c.gcTicker = ticker
|
||
|
c.done = done
|
||
|
c.Unlock()
|
||
|
|
||
|
go func() {
|
||
|
for {
|
||
|
select {
|
||
|
case <-ticker.C:
|
||
|
c.Lock()
|
||
|
for key := range c.conn {
|
||
|
if c.isExpired(key) {
|
||
|
c.delete(key)
|
||
|
log.Printf("Connection %s expired and closed\n", key)
|
||
|
}
|
||
|
}
|
||
|
c.Unlock()
|
||
|
case <-done:
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
|
||
|
// StopGC stops sweeping goroutine.
|
||
|
func (c *ConnStore) StopGC() {
|
||
|
if c.activeGC {
|
||
|
c.Lock()
|
||
|
c.gcTicker.Stop()
|
||
|
c.gcTicker = nil
|
||
|
close(c.done)
|
||
|
c.done = nil
|
||
|
c.Unlock()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *ConnStore) extend(key string, ttl time.Duration) {
|
||
|
conn := c.conn[key]
|
||
|
if conn != nil {
|
||
|
conn.extendConnection(ttl)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *ConnStore) isExpired(key string) bool {
|
||
|
conn := c.conn[key]
|
||
|
if conn == nil {
|
||
|
return false
|
||
|
}
|
||
|
return !conn.keepAlive && conn.expired.Before(time.Now())
|
||
|
}
|
||
|
|
||
|
func (c *ConnStore) getAllConn() map[string]*connection {
|
||
|
return c.conn
|
||
|
}
|
||
|
|
||
|
func (c *ConnStore) delete(key string) {
|
||
|
conn := c.conn[key]
|
||
|
if conn != nil {
|
||
|
conn.close()
|
||
|
delete(c.conn, key)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *ConnStore) addConnection(host string, res *Resource, ttl ...time.Duration) {
|
||
|
conn := &connection{
|
||
|
resource: res,
|
||
|
keepAlive: true,
|
||
|
}
|
||
|
|
||
|
if len(ttl) > 0 {
|
||
|
conn.keepAlive = false
|
||
|
conn.expired = time.Now().Add(ttl[0])
|
||
|
}
|
||
|
|
||
|
c.conn[host] = conn
|
||
|
}
|
||
|
|
||
|
func (c *ConnStore) getConnection(host string) (res *Resource, found bool) {
|
||
|
conn, ok := c.conn[host]
|
||
|
if ok && conn.resource != nil {
|
||
|
found = true
|
||
|
res = conn.resource
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (conn *connection) extendConnection(ttl time.Duration) {
|
||
|
conn.keepAlive = false
|
||
|
conn.expired = time.Now().Add(ttl)
|
||
|
}
|
||
|
|
||
|
func (conn *connection) close() {
|
||
|
conn.resource.Close()
|
||
|
}
|