mirror of
https://github.com/ClusterCockpit/cc-metric-store.git
synced 2024-11-10 13:17:25 +01:00
103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package memstore
|
|
|
|
import "sync"
|
|
|
|
// Could also be called "node" as this forms a node in a tree structure.
|
|
// Called level because "node" might be confusing here.
|
|
// Can be both a leaf or a inner node. In this tree structue, inner nodes can
|
|
// also hold data (in `metrics`).
|
|
type level struct {
|
|
lock sync.RWMutex
|
|
metrics []*chunk // Every level can store metrics.
|
|
sublevels map[string]*level // Lower levels.
|
|
}
|
|
|
|
// Find the correct level for the given selector, creating it if
|
|
// it does not exist. Example selector in the context of the
|
|
// ClusterCockpit could be: []string{ "emmy", "host123", "cpu0" }.
|
|
// This function would probably benefit a lot from `level.children` beeing a `sync.Map`?
|
|
func (l *level) findLevelOrCreate(selector []string, nMetrics int) *level {
|
|
if len(selector) == 0 {
|
|
return l
|
|
}
|
|
|
|
// Allow concurrent reads:
|
|
l.lock.RLock()
|
|
var child *level
|
|
var ok bool
|
|
if l.sublevels == nil {
|
|
// sublevels map needs to be created...
|
|
l.lock.RUnlock()
|
|
} else {
|
|
child, ok := l.sublevels[selector[0]]
|
|
l.lock.RUnlock()
|
|
if ok {
|
|
return child.findLevelOrCreate(selector[1:], nMetrics)
|
|
}
|
|
}
|
|
|
|
// The level does not exist, take write lock for unqiue access:
|
|
l.lock.Lock()
|
|
// While this thread waited for the write lock, another thread
|
|
// could have created the child node.
|
|
if l.sublevels != nil {
|
|
child, ok = l.sublevels[selector[0]]
|
|
if ok {
|
|
l.lock.Unlock()
|
|
return child.findLevelOrCreate(selector[1:], nMetrics)
|
|
}
|
|
}
|
|
|
|
child = &level{
|
|
metrics: make([]*chunk, nMetrics),
|
|
sublevels: nil,
|
|
}
|
|
|
|
if l.sublevels != nil {
|
|
l.sublevels[selector[0]] = child
|
|
} else {
|
|
l.sublevels = map[string]*level{selector[0]: child}
|
|
}
|
|
l.lock.Unlock()
|
|
return child.findLevelOrCreate(selector[1:], nMetrics)
|
|
}
|
|
|
|
func (l *level) free(t int64) (delme bool, n int) {
|
|
l.lock.Lock()
|
|
defer l.lock.Unlock()
|
|
|
|
for i, c := range l.metrics {
|
|
if c != nil {
|
|
delchunk, m := c.free(t)
|
|
n += m
|
|
if delchunk {
|
|
freeChunk(c)
|
|
l.metrics[i] = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
for key, l := range l.sublevels {
|
|
delsublevel, m := l.free(t)
|
|
n += m
|
|
if delsublevel {
|
|
l.sublevels[key] = nil
|
|
}
|
|
}
|
|
|
|
return len(l.metrics) == 0 && len(l.sublevels) == 0, n
|
|
}
|
|
|
|
type MemoryStore struct {
|
|
root level // root of the tree structure
|
|
// TODO...
|
|
}
|
|
|
|
func (ms *MemoryStore) GetOffset(metric string) int {
|
|
return -1 // TODO!
|
|
}
|
|
|
|
func (ms *MemoryStore) GetMetricForOffset(offset int) string {
|
|
return "" // TODO!
|
|
}
|