"cardinality explosion" would make for an epic rock band name... Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I53cceb00ab9b17039b1fb1389977bf6b6a6a6964
72 lines
1.7 KiB
Go
72 lines
1.7 KiB
Go
package aggregate
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// Maintain a bounded set of unique request paths. This prevents metric cardinality explosion by rejecting new paths
|
|
// once the configured limit is reached.
|
|
type PathRegistry struct {
|
|
mu sync.RWMutex
|
|
paths map[string]struct{}
|
|
maxPaths int
|
|
overflowCount int
|
|
}
|
|
|
|
// Creates a new PathRegistry with the specified maximum number of unique paths.
|
|
// Once this limit is reached, subsequent Add() calls for new paths will be rejected.
|
|
func NewPathRegistry(maxPaths int) *PathRegistry {
|
|
return &PathRegistry{
|
|
paths: make(map[string]struct{}, maxPaths),
|
|
maxPaths: maxPaths,
|
|
}
|
|
}
|
|
|
|
// Add attempts to add a path to the registry.
|
|
// Returns true if the path was accepted: either already existed or was added,
|
|
// false if rejected due to reaching the limit.
|
|
func (r *PathRegistry) Add(path string) bool {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
// If path already exists, accept it
|
|
if _, exists := r.paths[path]; exists {
|
|
return true
|
|
}
|
|
|
|
// If we haven't reached the limit, add the path
|
|
if len(r.paths) < r.maxPaths {
|
|
r.paths[path] = struct{}{}
|
|
return true
|
|
}
|
|
|
|
// Limit reached - reject and increment overflow
|
|
r.overflowCount++
|
|
return false
|
|
}
|
|
|
|
// Contains checks if a path exists in the registry.
|
|
func (r *PathRegistry) Contains(path string) bool {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
|
|
_, exists := r.paths[path]
|
|
return exists
|
|
}
|
|
|
|
// Count returns the number of unique paths in the registry.
|
|
func (r *PathRegistry) Count() int {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
|
|
return len(r.paths)
|
|
}
|
|
|
|
// Returns the number of paths that were rejected
|
|
// due to the registry being at capacity.
|
|
func (r *PathRegistry) OverflowCount() int {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
|
|
return r.overflowCount
|
|
}
|