cc-metric-store/internal/memstore/memstore.go
2022-07-13 17:41:57 +02:00

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!
}