From 751bcc7b2f10f992806eee5f9df554fcf8d97829 Mon Sep 17 00:00:00 2001 From: DanB Date: Wed, 30 Nov 2022 19:41:38 +0100 Subject: [PATCH] SecureMapStorage as cache for EventCost --- engine/eventcost.go | 8 ++--- engine/libeventcost.go | 2 +- utils/mapstorage.go | 72 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/engine/eventcost.go b/engine/eventcost.go index 961de3576..0c3cc4be2 100644 --- a/engine/eventcost.go +++ b/engine/eventcost.go @@ -35,7 +35,7 @@ func NewBareEventCost() *EventCost { Rates: make(ChargedRates), Timings: make(ChargedTimings), Charges: make([]*ChargingInterval, 0), - cache: utils.MapStorage{}, + cache: utils.NewSecureMapStorage(), } } @@ -160,12 +160,12 @@ type EventCost struct { Rates ChargedRates Timings ChargedTimings - cache utils.MapStorage + cache *utils.SecureMapStorage } func (ec *EventCost) initCache() { if ec != nil { - ec.cache = utils.MapStorage{} + ec.cache = utils.NewSecureMapStorage() } } @@ -952,7 +952,7 @@ func (ec *EventCost) Trim(atUsage time.Duration) (srplusEC *EventCost, err error // FieldAsInterface func to implement DataProvider func (ec *EventCost) FieldAsInterface(fldPath []string) (val interface{}, err error) { if ec.cache == nil { - ec.cache = utils.MapStorage{} // fix gob deserialization + ec.initCache() // fix gob deserialization } if val, err = ec.cache.FieldAsInterface(fldPath); err != nil { if err != utils.ErrNotFound { // item found in cache diff --git a/engine/libeventcost.go b/engine/libeventcost.go index 788b5668d..6ff36d051 100644 --- a/engine/libeventcost.go +++ b/engine/libeventcost.go @@ -681,6 +681,6 @@ func NewFreeEventCost(cgrID, runID, account string, tStart time.Time, usage time StartTime: "00:00:00", }, }, - cache: utils.MapStorage{}, + cache: utils.NewSecureMapStorage(), } } diff --git a/utils/mapstorage.go b/utils/mapstorage.go index 0f66c25fa..ad4cabbbf 100644 --- a/utils/mapstorage.go +++ b/utils/mapstorage.go @@ -24,6 +24,7 @@ import ( "reflect" "strconv" "strings" + "sync" "time" ) @@ -326,6 +327,77 @@ func (ms MapStorage) Clone() (msClone MapStorage) { return } +// NewSecureMapStorage constructs a new SecureMapStorage +func NewSecureMapStorage() *SecureMapStorage { + return &SecureMapStorage{ + ms: make(MapStorage), + } +} + +// SecureMapStorage is a MapStorage with secure read/writes +// useful for example as cache for various parts +type SecureMapStorage struct { + sync.RWMutex + ms MapStorage +} + +// String returns the JNSON representation of MapStorage +func (sm *SecureMapStorage) String() (s string) { + sm.RLock() + s = sm.ms.String() + sm.RUnlock() + return +} + +// FieldAsInterface returns the value at the path specified +func (sm *SecureMapStorage) FieldAsInterface(fldPath []string) (val interface{}, err error) { + sm.RLock() + val, err = sm.ms.FieldAsInterface(fldPath) + sm.RUnlock() + return +} + +// FieldAsString returns the value at the path specified casted as string +func (sm *SecureMapStorage) FieldAsString(fldPath []string) (s string, err error) { + sm.RLock() + s, err = sm.ms.FieldAsString(fldPath) + sm.RUnlock() + return +} + +// Set will set the value at path +func (sm *SecureMapStorage) Set(fldPath []string, val interface{}) (err error) { + sm.Lock() + err = sm.ms.Set(fldPath, val) + sm.Unlock() + return +} + +// GetKeys returns a list of keys for the prefix +func (sm *SecureMapStorage) GetKeys(nested bool, nestedLimit int, prefix string) (keys []string) { + sm.RLock() + keys = sm.ms.GetKeys(nested, nestedLimit, prefix) + sm.RUnlock() + return +} + +// Remove will remove based on field path +func (sm *SecureMapStorage) Remove(fldPath []string) (err error) { + sm.Lock() + err = sm.ms.Remove(fldPath) + sm.Unlock() + return +} + +// Clone returns a clone of sm +func (sm *SecureMapStorage) Clone() (smClone *SecureMapStorage) { + sm.RLock() + smClone = new(SecureMapStorage) + smClone.ms = smClone.ms.Clone() + sm.RUnlock() + return +} + // used only in extreme cases where the dataprovider is an object that doesn't implement the dataStorage interface func getPathFromValue(in reflect.Value, prefix string) (out []string) { switch in.Kind() {