package metrics import ( "sync" "github.com/ipfs/ipfs-cluster/api" peer "github.com/libp2p/go-libp2p-peer" ) // PeerMetrics maps a peer IDs to a metrics window. type PeerMetrics map[peer.ID]*Window // Store can be used to store and access metrics. type Store struct { mux sync.RWMutex byName map[string]PeerMetrics } // NewStore can be used to create a Store. func NewStore() *Store { return &Store{ byName: make(map[string]PeerMetrics), } } // Add inserts a new metric in Metrics. func (mtrs *Store) Add(m *api.Metric) { mtrs.mux.Lock() defer mtrs.mux.Unlock() name := m.Name peer := m.Peer mbyp, ok := mtrs.byName[name] if !ok { mbyp = make(PeerMetrics) mtrs.byName[name] = mbyp } window, ok := mbyp[peer] if !ok { // We always lock the outer map, so we can use unsafe // Window. window = NewWindow(DefaultWindowCap) mbyp[peer] = window } window.Add(m) } // LatestValid returns all the last known valid metrics of a given type. A metric // is valid if it has not expired. func (mtrs *Store) LatestValid(name string) []*api.Metric { mtrs.mux.RLock() defer mtrs.mux.RUnlock() byPeer, ok := mtrs.byName[name] if !ok { return []*api.Metric{} } metrics := make([]*api.Metric, 0, len(byPeer)) for _, window := range byPeer { m, err := window.Latest() if err != nil || m.Discard() { continue } metrics = append(metrics, m) } return metrics } // AllMetrics returns the latest metrics for all peers and metrics types. It // may return expired metrics. func (mtrs *Store) AllMetrics() []*api.Metric { mtrs.mux.RLock() defer mtrs.mux.RUnlock() result := make([]*api.Metric, 0) for _, byPeer := range mtrs.byName { for _, window := range byPeer { metric, err := window.Latest() if err != nil || !metric.Valid { continue } result = append(result, metric) } } return result } // PeerMetrics returns the latest metrics for a given peer ID for // all known metrics types. It may return expired metrics. func (mtrs *Store) PeerMetrics(pid peer.ID) []*api.Metric { mtrs.mux.RLock() defer mtrs.mux.RUnlock() result := make([]*api.Metric, 0) for _, byPeer := range mtrs.byName { window, ok := byPeer[pid] if !ok { continue } metric, err := window.Latest() if err != nil || !metric.Valid { continue } result = append(result, metric) } return result }