github.com/m-lab/tcp-info@v1.9.0/cache/cache.go (about) 1 // Package cache keeps a cache of connection info records. 2 // Cache is NOT threadsafe. 3 package cache 4 5 import ( 6 "errors" 7 8 "github.com/m-lab/tcp-info/metrics" 9 "github.com/m-lab/tcp-info/netlink" 10 ) 11 12 // Package error messages 13 var ( 14 ErrInetDiagParseFailed = errors.New("Error parsing inetdiag message") 15 ErrLocal = errors.New("Connection is loopback") 16 ErrUnknownMessageType = errors.New("Unknown netlink message type") 17 ) 18 19 // Cache is a cache of all connection status. 20 type Cache struct { 21 // Map from inode to ArchivalRecord 22 current map[uint64]*netlink.ArchivalRecord // Cache of most recent messages. 23 previous map[uint64]*netlink.ArchivalRecord // Cache of previous round of messages. 24 cycles int64 25 } 26 27 // NewCache creates a cache object with capacity of 1000. 28 // The map size is adjusted on every sampling round, but we have to start somewhere. 29 func NewCache() *Cache { 30 return &Cache{current: make(map[uint64]*netlink.ArchivalRecord, 1000), 31 previous: make(map[uint64]*netlink.ArchivalRecord, 0)} 32 } 33 34 // Update swaps msg with the cache contents, and returns the evicted value. 35 func (c *Cache) Update(msg *netlink.ArchivalRecord) (*netlink.ArchivalRecord, error) { 36 idm, err := msg.RawIDM.Parse() 37 if err != nil { 38 return nil, err 39 } 40 cookie := idm.ID.Cookie() 41 c.current[cookie] = msg 42 evicted, ok := c.previous[cookie] 43 if ok { 44 delete(c.previous, cookie) 45 } 46 return evicted, nil 47 } 48 49 // EndCycle marks the completion of updates from one set of netlink messages. 50 // It returns all messages that did not have corresponding inodes in the most recent 51 // batch of messages. 52 func (c *Cache) EndCycle() map[uint64]*netlink.ArchivalRecord { 53 metrics.CacheSizeHistogram.Observe(float64(len(c.current))) 54 tmp := c.previous 55 c.previous = c.current 56 // Allocate a bit more than previous size, to accommodate new connections. 57 // This will grow and shrink with the number of active connections, but 58 // minimize reallocation. 59 c.current = make(map[uint64]*netlink.ArchivalRecord, len(c.previous)+len(c.previous)/10+10) 60 c.cycles++ 61 return tmp 62 } 63 64 // CycleCount returns the number of times EndCycle() has been called. 65 func (c *Cache) CycleCount() int64 { 66 // Don't need a prometheus counter, because we already have the count of CacheSizeHistogram observations. 67 return c.cycles 68 }