github.com/mailgun/holster/v4@v4.20.0/grpcconn/idpool.go (about) 1 package grpcconn 2 3 import ( 4 "strconv" 5 "sync" 6 ) 7 8 // IDPool maintains a pool of ID values that can be released and reused. 9 // This is handy to keep cardinality low as gRPC connections are periodically 10 // released and reconnected and require an id. 11 // This solves the problem of infinitely incrementing ids used in Prometheus 12 // metric labels causing infinite growth of historical metric values. 13 type IDPool struct { 14 pool map[ID]bool 15 allocated int 16 allocMu sync.RWMutex 17 } 18 19 type ID int 20 21 func NewIDPool() *IDPool { 22 return &IDPool{ 23 pool: make(map[ID]bool), 24 } 25 } 26 27 func (i *IDPool) Allocate() ID { 28 i.allocMu.Lock() 29 defer i.allocMu.Unlock() 30 31 for id, allocFlag := range i.pool { 32 if allocFlag { 33 continue 34 } 35 36 i.allocated++ 37 i.pool[id] = true 38 return id 39 } 40 41 // Dynamically expand pool. 42 newID := ID(len(i.pool) + 1) 43 i.pool[newID] = true 44 return newID 45 } 46 47 func (i *IDPool) Release(id ID) { 48 i.allocMu.Lock() 49 defer i.allocMu.Unlock() 50 51 if allocFlag, ok := i.pool[id]; !ok || !allocFlag { 52 return 53 } 54 55 i.allocated-- 56 i.pool[id] = false 57 } 58 59 func (id ID) String() string { 60 return strconv.Itoa(int(id)) 61 }