make each memory store struct have its own internal map

effectively removing the global state
This commit is contained in:
Chris Heppell 2020-12-31 20:37:11 +00:00
parent 029c87df89
commit 8ca9fd7db5
2 changed files with 26 additions and 28 deletions

View File

@ -7,28 +7,26 @@ import (
"github.com/TwinProduction/gatus/core"
)
var (
serviceStatuses = make(map[string]*core.ServiceStatus)
// serviceResultsMutex is used to prevent concurrent map access
serviceResultsMutex sync.RWMutex
)
// InMemoryStore implements an in-memory store
type InMemoryStore struct{}
type InMemoryStore struct {
serviceStatuses map[string]*core.ServiceStatus
serviceResultsMutex sync.RWMutex
}
// NewInMemoryStore returns an in-memory store. Note that the store acts as a singleton, so although new-ing
// up in-memory stores will give you a unique reference to a struct each time, all structs returned
// by this function will act on the same in-memory store.
func NewInMemoryStore() InMemoryStore {
return InMemoryStore{}
return InMemoryStore{
serviceStatuses: make(map[string]*core.ServiceStatus),
}
}
// GetAll returns all the observed results for all services from the in memory store
func (ims *InMemoryStore) GetAll() map[string]*core.ServiceStatus {
results := make(map[string]*core.ServiceStatus)
serviceResultsMutex.RLock()
for key, svcStatus := range serviceStatuses {
ims.serviceResultsMutex.RLock()
for key, svcStatus := range ims.serviceStatuses {
copiedResults := copyResults(svcStatus.Results)
results[key] = &core.ServiceStatus{
Name: svcStatus.Name,
@ -36,7 +34,7 @@ func (ims *InMemoryStore) GetAll() map[string]*core.ServiceStatus {
Results: copiedResults,
}
}
serviceResultsMutex.RUnlock()
ims.serviceResultsMutex.RUnlock()
return results
}
@ -44,9 +42,9 @@ func (ims *InMemoryStore) GetAll() map[string]*core.ServiceStatus {
// GetServiceStatus returns the service status for a given service name in the given group
func (ims *InMemoryStore) GetServiceStatus(group, name string) *core.ServiceStatus {
key := fmt.Sprintf("%s_%s", group, name)
serviceResultsMutex.RLock()
serviceStatus, exists := serviceStatuses[key]
serviceResultsMutex.RUnlock()
ims.serviceResultsMutex.RLock()
serviceStatus, exists := ims.serviceStatuses[key]
ims.serviceResultsMutex.RUnlock()
if !exists {
return nil
}
@ -56,14 +54,14 @@ func (ims *InMemoryStore) GetServiceStatus(group, name string) *core.ServiceStat
// Insert inserts the observed result for the specified service into the in memory store
func (ims *InMemoryStore) Insert(service *core.Service, result *core.Result) {
key := fmt.Sprintf("%s_%s", service.Group, service.Name)
serviceResultsMutex.Lock()
serviceStatus, exists := serviceStatuses[key]
ims.serviceResultsMutex.Lock()
serviceStatus, exists := ims.serviceStatuses[key]
if !exists {
serviceStatus = core.NewServiceStatus(service)
serviceStatuses[key] = serviceStatus
ims.serviceStatuses[key] = serviceStatus
}
serviceStatus.AddResult(result)
serviceResultsMutex.Unlock()
ims.serviceResultsMutex.Unlock()
}
func copyResults(results []*core.Result) []*core.Result {
@ -112,7 +110,7 @@ func copyErrors(errors []string) []string {
// Clear will empty all the results from the in memory store
func (ims *InMemoryStore) Clear() {
serviceResultsMutex.Lock()
serviceStatuses = make(map[string]*core.ServiceStatus)
serviceResultsMutex.Unlock()
ims.serviceResultsMutex.Lock()
ims.serviceStatuses = make(map[string]*core.ServiceStatus)
ims.serviceResultsMutex.Unlock()
}

View File

@ -360,7 +360,7 @@ func TestStorage_InsertResultForServiceWithConditionResultsIntoEmptyMemoryStore_
}
}
func TestStorage_MultipleMemoryStoreInstancesReferToSameMemoryMap(t *testing.T) {
func TestStorage_MultipleMemoryStoreInstancesReferToDifferentInternalMaps(t *testing.T) {
memoryStore.Clear()
currentMap := memoryStore.GetAll()
@ -368,23 +368,23 @@ func TestStorage_MultipleMemoryStoreInstancesReferToSameMemoryMap(t *testing.T)
otherMemoryStoresMap := otherMemoryStore.GetAll()
if len(currentMap) != len(otherMemoryStoresMap) {
t.Errorf("Multiple memory stores should refer to the same internal map, but 'memoryStore' returned %d results, and 'otherMemoryStore' returned %d results", len(currentMap), len(otherMemoryStoresMap))
t.Errorf("Multiple memory stores should refer to the different internal maps, but 'memoryStore' returned %d results, and 'otherMemoryStore' returned %d results", len(currentMap), len(otherMemoryStoresMap))
}
memoryStore.Insert(&testService, &core.Result{})
currentMap = memoryStore.GetAll()
otherMemoryStoresMap = otherMemoryStore.GetAll()
if len(currentMap) != len(otherMemoryStoresMap) {
t.Errorf("Multiple memory stores should refer to the same internal map, but 'memoryStore' returned %d results after inserting, and 'otherMemoryStore' returned %d results after inserting", len(currentMap), len(otherMemoryStoresMap))
if len(currentMap) == len(otherMemoryStoresMap) {
t.Errorf("Multiple memory stores should refer to different internal maps, but 'memoryStore' returned %d results after inserting, and 'otherMemoryStore' returned %d results after inserting", len(currentMap), len(otherMemoryStoresMap))
}
otherMemoryStore.Clear()
currentMap = memoryStore.GetAll()
otherMemoryStoresMap = otherMemoryStore.GetAll()
if len(currentMap) != len(otherMemoryStoresMap) {
t.Errorf("Multiple memory stores should refer to the same internal map, but 'memoryStore' returned %d results after clearing, and 'otherMemoryStore' returned %d results after clearing", len(currentMap), len(otherMemoryStoresMap))
if len(currentMap) == len(otherMemoryStoresMap) {
t.Errorf("Multiple memory stores should refer to different internal maps, but 'memoryStore' returned %d results after clearing, and 'otherMemoryStore' returned %d results after clearing", len(currentMap), len(otherMemoryStoresMap))
}
}