Files
poseidon/pkg/storage/storage.go
Maximilian Paß 498e8f5ff5 #110 Refactor influxdb monitoring
to use it as singleton.
This enables the possibility to monitor processes that are independent of an incoming request.
2022-07-01 15:29:31 +02:00

148 lines
3.6 KiB
Go

package storage
import (
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
"github.com/influxdata/influxdb-client-go/v2/api/write"
"github.com/openHPI/poseidon/pkg/monitoring"
"strconv"
"sync"
)
// Storage is an interface for storing objects.
type Storage[T any] interface {
// List returns all objects from the storage.
List() []T
// Add adds an object to the storage.
// It overwrites the old object if one with the same id was already stored.
Add(id string, o T)
// Get returns an object from the storage.
// Iff the object does not exist in the storage, ok will be false.
Get(id string) (o T, ok bool)
// Delete deletes the object with the passed id from the storage.
// It does nothing if no object with the id is present in the store.
Delete(id string)
// Pop deletes the object with the given id from the storage and returns it.
// Iff no such execution exists, ok is false and true otherwise.
Pop(id string) (o T, ok bool)
// Purge removes all objects from the storage.
Purge()
// Length returns the number of currently stored objects in the storage.
Length() uint
// Sample returns and removes an arbitrary object from the storage.
// ok is true iff an object was returned.
Sample() (o T, ok bool)
}
type WriteCallback[T any] func(p *write.Point, object T, isDeletion bool)
// localStorage stores objects in the local application memory.
type localStorage[T any] struct {
sync.RWMutex
objects map[string]T
measurement string
callback WriteCallback[T]
}
// NewLocalStorage responds with a Storage implementation.
// This implementation stores the data thread-safe in the local application memory.
func NewLocalStorage[T any]() *localStorage[T] {
return &localStorage[T]{
objects: make(map[string]T),
}
}
// NewMonitoredLocalStorage responds with a Storage implementation.
// All write operations are monitored in the passed measurement.
// Iff callback is set, it will be called on a write operation.
func NewMonitoredLocalStorage[T any](measurement string, callback WriteCallback[T]) *localStorage[T] {
return &localStorage[T]{
objects: make(map[string]T),
measurement: measurement,
callback: callback,
}
}
func (s *localStorage[T]) List() (o []T) {
s.RLock()
defer s.RUnlock()
for _, value := range s.objects {
o = append(o, value)
}
return o
}
func (s *localStorage[T]) Add(id string, o T) {
s.Lock()
defer s.Unlock()
s.objects[id] = o
s.sendMonitoringData(id, o, false)
}
func (s *localStorage[T]) Get(id string) (o T, ok bool) {
s.RLock()
defer s.RUnlock()
o, ok = s.objects[id]
return
}
func (s *localStorage[T]) Delete(id string) {
s.Lock()
defer s.Unlock()
s.sendMonitoringData(id, s.objects[id], true)
delete(s.objects, id)
}
func (s *localStorage[T]) Pop(id string) (T, bool) {
o, ok := s.Get(id)
s.Delete(id)
return o, ok
}
func (s *localStorage[T]) Purge() {
s.Lock()
defer s.Unlock()
for key, object := range s.objects {
s.sendMonitoringData(key, object, true)
}
s.objects = make(map[string]T)
}
func (s *localStorage[T]) Sample() (o T, ok bool) {
s.Lock()
defer s.Unlock()
for key, object := range s.objects {
s.sendMonitoringData(key, object, true)
delete(s.objects, key)
return object, true
}
return o, false
}
func (s *localStorage[T]) Length() uint {
s.RLock()
defer s.RUnlock()
return uint(len(s.objects))
}
func (s *localStorage[T]) sendMonitoringData(id string, o T, isDeletion bool) {
if s.measurement != "" {
p := influxdb2.NewPointWithMeasurement(s.measurement)
p.AddTag("id", id)
p.AddTag("isDeletion", strconv.FormatBool(isDeletion))
p.AddField("count", 1)
if s.callback != nil {
s.callback(p, o, isDeletion)
}
monitoring.WriteInfluxPoint(p)
}
}