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  }