blob: 640618ac15c599e9a95567018e0cf8c425cd4ea9 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"sync"
"time"
"v.io/x/ref/lib/stats"
"v.io/x/ref/lib/stats/counter"
"v.io/x/ref/lib/stats/histogram"
"v.io/v23/naming"
)
type rpcStats struct {
mu sync.RWMutex
prefix string
methods map[string]*perMethodStats
blessingsCacheStats *blessingsCacheStats
}
func newRPCStats(prefix string) *rpcStats {
return &rpcStats{
prefix: prefix,
methods: make(map[string]*perMethodStats),
blessingsCacheStats: newBlessingsCacheStats(prefix),
}
}
type perMethodStats struct {
latency *histogram.Histogram
}
func (s *rpcStats) stop() {
stats.Delete(s.prefix)
}
func (s *rpcStats) record(method string, latency time.Duration) {
// Try first with a read lock. This will succeed in the most common
// case. If it fails, try again with a write lock and create the stats
// objects if they are still not there.
s.mu.RLock()
m, ok := s.methods[method]
s.mu.RUnlock()
if !ok {
m = s.newPerMethodStats(method)
}
m.latency.Add(int64(latency / time.Millisecond))
}
func (s *rpcStats) recordBlessingCache(hit bool) {
s.blessingsCacheStats.incr(hit)
}
// newPerMethodStats creates a new perMethodStats object if one doesn't exist
// already. It returns the newly created object, or the already existing one.
func (s *rpcStats) newPerMethodStats(method string) *perMethodStats {
s.mu.Lock()
defer s.mu.Unlock()
m, ok := s.methods[method]
if !ok {
name := naming.Join(s.prefix, "methods", method, "latency-ms")
s.methods[method] = &perMethodStats{
latency: stats.NewHistogram(name, histogram.Options{
NumBuckets: 25,
GrowthFactor: 1,
SmallestBucketSize: 1,
MinValue: 0,
}),
}
m = s.methods[method]
}
return m
}
// blessingsCacheStats keeps blessing cache hits and total calls received to determine
// how often the blessingCache is being used.
type blessingsCacheStats struct {
callsReceived, cacheHits *counter.Counter
}
func newBlessingsCacheStats(prefix string) *blessingsCacheStats {
cachePrefix := naming.Join(prefix, "security", "blessings", "cache")
return &blessingsCacheStats{
callsReceived: stats.NewCounter(naming.Join(cachePrefix, "attempts")),
cacheHits: stats.NewCounter(naming.Join(cachePrefix, "hits")),
}
}
// Incr increments the cache attempt counter and the cache hit counter if hit is true.
func (s *blessingsCacheStats) incr(hit bool) {
s.callsReceived.Incr(1)
if hit {
s.cacheHits.Incr(1)
}
}