package prometheus
import (
"sync"
"time"
"github.com/prometheus/prometheus/model/labels"
)
var GlobalRefMapping = &GlobalRefMap{}
func init() {
GlobalRefMapping = newGlobalRefMap()
}
var staleDuration = time.Minute * 10
type GlobalRefMap struct {
mut sync.Mutex
globalRefID uint64
mappings map[string]*remoteWriteMapping
labelsHashToGlobal map[uint64]uint64
staleGlobals map[uint64]*staleMarker
}
type staleMarker struct {
globalID uint64
lastMarkedStale time.Time
labelHash uint64
}
func newGlobalRefMap() *GlobalRefMap {
return &GlobalRefMap{
globalRefID: 0,
mappings: make(map[string]*remoteWriteMapping),
labelsHashToGlobal: make(map[uint64]uint64),
staleGlobals: make(map[uint64]*staleMarker),
}
}
func (g *GlobalRefMap) GetOrAddLink(componentID string, localRefID uint64, lbls labels.Labels) uint64 {
g.mut.Lock()
defer g.mut.Unlock()
m, found := g.mappings[componentID]
if !found {
m = &remoteWriteMapping{
RemoteWriteID: componentID,
localToGlobal: make(map[uint64]uint64),
globalToLocal: make(map[uint64]uint64),
}
g.mappings[componentID] = m
}
labelHash := lbls.Hash()
globalID, found := g.labelsHashToGlobal[labelHash]
if found {
m.localToGlobal[localRefID] = globalID
m.globalToLocal[globalID] = localRefID
return globalID
}
g.globalRefID++
g.labelsHashToGlobal[labelHash] = g.globalRefID
m.localToGlobal[localRefID] = g.globalRefID
m.globalToLocal[g.globalRefID] = localRefID
return g.globalRefID
}
func (g *GlobalRefMap) GetOrAddGlobalRefID(l labels.Labels) uint64 {
g.mut.Lock()
defer g.mut.Unlock()
if l == nil {
return 0
}
labelHash := l.Hash()
globalID, found := g.labelsHashToGlobal[labelHash]
if found {
return globalID
}
g.globalRefID++
g.labelsHashToGlobal[labelHash] = g.globalRefID
return g.globalRefID
}
func (g *GlobalRefMap) GetGlobalRefID(componentID string, localRefID uint64) uint64 {
g.mut.Lock()
defer g.mut.Unlock()
m, found := g.mappings[componentID]
if !found {
return 0
}
global := m.localToGlobal[localRefID]
return global
}
func (g *GlobalRefMap) GetLocalRefID(componentID string, globalRefID uint64) uint64 {
g.mut.Lock()
defer g.mut.Unlock()
m, found := g.mappings[componentID]
if !found {
return 0
}
local := m.globalToLocal[globalRefID]
return local
}
func (g *GlobalRefMap) AddStaleMarker(globalRefID uint64, l labels.Labels) {
g.mut.Lock()
defer g.mut.Unlock()
g.staleGlobals[globalRefID] = &staleMarker{
lastMarkedStale: time.Now(),
labelHash: l.Hash(),
globalID: globalRefID,
}
}
func (g *GlobalRefMap) RemoveStaleMarker(globalRefID uint64) {
g.mut.Lock()
defer g.mut.Unlock()
delete(g.staleGlobals, globalRefID)
}
func (g *GlobalRefMap) CheckStaleMarkers() {
g.mut.Lock()
defer g.mut.Unlock()
curr := time.Now()
idsToBeGCed := make([]*staleMarker, 0)
for _, stale := range g.staleGlobals {
if curr.Sub(stale.lastMarkedStale) < staleDuration {
continue
}
idsToBeGCed = append(idsToBeGCed, stale)
}
for _, marker := range idsToBeGCed {
delete(g.staleGlobals, marker.globalID)
delete(g.labelsHashToGlobal, marker.labelHash)
for _, mapping := range g.mappings {
mapping.deleteStaleIDs(marker.globalID)
}
}
}