From e16fa51b31ee64767814714005a34e609797a7fd Mon Sep 17 00:00:00 2001
From: Manuel Kieweg <manuel.kieweg@h-da.de>
Date: Tue, 27 Jul 2021 12:43:30 +0100
Subject: [PATCH] more sensible benchmarks

---
 store/mutexStore.go          |  77 ++++++++++++++++++++++
 store/nologStore.go          |  77 ++++++++++++++++++++++
 store/storeBenchmark_test.go | 120 ++++++++++++++++++++++++++++-------
 3 files changed, 250 insertions(+), 24 deletions(-)
 create mode 100644 store/mutexStore.go
 create mode 100644 store/nologStore.go

diff --git a/store/mutexStore.go b/store/mutexStore.go
new file mode 100644
index 000000000..160e6ee1c
--- /dev/null
+++ b/store/mutexStore.go
@@ -0,0 +1,77 @@
+package store
+
+import (
+	"sync"
+
+	"code.fbi.h-da.de/danet/gosdn/interfaces/store"
+	"code.fbi.h-da.de/danet/gosdn/nucleus/errors"
+
+	"github.com/google/uuid"
+)
+
+// newmutexStore returns a mutexStore
+func newMutexStore() *mutexStore {
+	return &mutexStore{Store: make(map[uuid.UUID]store.Storable), storeLock: sync.Mutex{}}
+}
+
+type mutexStore struct {
+	Store     map[uuid.UUID]store.Storable
+	storeLock sync.Mutex
+}
+
+// Exists takes a Storable's UUID and checks its existence in the store.
+func (s *mutexStore) Exists(id uuid.UUID) bool {
+	s.storeLock.Lock()
+	defer s.storeLock.Unlock()
+	_, ok := s.Store[id]
+	return ok
+}
+
+// Add adds a Storable to the Store
+func (s *mutexStore) Add(item store.Storable) error {
+	if s.Exists(item.ID()) {
+		return &errors.ErrAlreadyExists{Item: item}
+	}
+	s.storeLock.Lock()
+	s.Store[item.ID()] = item
+	s.storeLock.Unlock()
+	return nil
+}
+
+// Get takes a Storable's UUID and returns the Storable. If the requested
+// Storable does not exist an error is returned. Get is only type safe for
+// this Storable interface. For type safe get operations on specialised stores
+// use GetDevice, GetPND, GetSBI, or GetChange respectively.
+func (s *mutexStore) Get(id uuid.UUID) (store.Storable, error) {
+	if !s.Exists(id) {
+		return nil, &errors.ErrNotFound{ID: id}
+	}
+	s.storeLock.Lock()
+	defer s.storeLock.Unlock()
+	return s.Store[id], nil
+}
+
+// Delete takes a Storable's UUID and deletes it. If the specified UUID does not
+// exist in the Store an error is returned.
+func (s *mutexStore) Delete(id uuid.UUID) error {
+	if !s.Exists(id) {
+		return &errors.ErrNotFound{ID: id}
+	}
+	s.storeLock.Lock()
+	delete(s.Store, id)
+	s.storeLock.Unlock()
+	return nil
+}
+
+// UUIDs returns all UUIDs in the store.
+func (s *mutexStore) UUIDs() []uuid.UUID {
+	s.storeLock.Lock()
+	defer s.storeLock.Unlock()
+	keys := make([]uuid.UUID, len(s.Store))
+	i := 0
+	for k := range s.Store {
+		keys[i] = k
+		i++
+	}
+	return keys
+}
diff --git a/store/nologStore.go b/store/nologStore.go
new file mode 100644
index 000000000..57a5da67e
--- /dev/null
+++ b/store/nologStore.go
@@ -0,0 +1,77 @@
+package store
+
+import (
+	"sync"
+
+	"code.fbi.h-da.de/danet/gosdn/interfaces/store"
+	"code.fbi.h-da.de/danet/gosdn/nucleus/errors"
+
+	"github.com/google/uuid"
+)
+
+// newnologStore returns a nologStore
+func newNologStore() *nologStore {
+	return &nologStore{Store: make(map[uuid.UUID]store.Storable), storeLock: sync.RWMutex{}}
+}
+
+type nologStore struct {
+	Store     map[uuid.UUID]store.Storable
+	storeLock sync.RWMutex
+}
+
+// Exists takes a Storable's UUID and checks its existence in the store.
+func (s *nologStore) Exists(id uuid.UUID) bool {
+	s.storeLock.RLock()
+	defer s.storeLock.RUnlock()
+	_, ok := s.Store[id]
+	return ok
+}
+
+// Add adds a Storable to the Store
+func (s *nologStore) Add(item store.Storable) error {
+	if s.Exists(item.ID()) {
+		return &errors.ErrAlreadyExists{Item: item}
+	}
+	s.storeLock.Lock()
+	s.Store[item.ID()] = item
+	s.storeLock.Unlock()
+	return nil
+}
+
+// Get takes a Storable's UUID and returns the Storable. If the requested
+// Storable does not exist an error is returned. Get is only type safe for
+// this Storable interface. For type safe get operations on specialised stores
+// use GetDevice, GetPND, GetSBI, or GetChange respectively.
+func (s *nologStore) Get(id uuid.UUID) (store.Storable, error) {
+	if !s.Exists(id) {
+		return nil, &errors.ErrNotFound{ID: id}
+	}
+	s.storeLock.RLock()
+	defer s.storeLock.RUnlock()
+	return s.Store[id], nil
+}
+
+// Delete takes a Storable's UUID and deletes it. If the specified UUID does not
+// exist in the Store an error is returned.
+func (s *nologStore) Delete(id uuid.UUID) error {
+	if !s.Exists(id) {
+		return &errors.ErrNotFound{ID: id}
+	}
+	s.storeLock.Lock()
+	delete(s.Store, id)
+	s.storeLock.Unlock()
+	return nil
+}
+
+// UUIDs returns all UUIDs in the store.
+func (s *nologStore) UUIDs() []uuid.UUID {
+	s.storeLock.RLock()
+	defer s.storeLock.RUnlock()
+	keys := make([]uuid.UUID, len(s.Store))
+	i := 0
+	for k := range s.Store {
+		keys[i] = k
+		i++
+	}
+	return keys
+}
diff --git a/store/storeBenchmark_test.go b/store/storeBenchmark_test.go
index 7704a25c4..ff9f792a0 100644
--- a/store/storeBenchmark_test.go
+++ b/store/storeBenchmark_test.go
@@ -28,6 +28,14 @@ func BenchmarkAdd(b *testing.B) {
 			name: "channel",
 			s:    newChannelStore(),
 		},
+		{
+			name: "mutex",
+			s:    newMutexStore(),
+		},
+		{
+			name: "nolog",
+			s:    newNologStore(),
+		},
 	}
 	for _, bm := range benchmarks {
 		b.Run(bm.name, func(b *testing.B) {
@@ -54,6 +62,14 @@ func BenchmarkGet(b *testing.B) {
 			name: "channel",
 			s:    newChannelStore(),
 		},
+		{
+			name: "mutex",
+			s:    newMutexStore(),
+		},
+		{
+			name: "nolog",
+			s:    newNologStore(),
+		},
 	}
 	for _, bm := range benchmarks {
 		b.Run(bm.name, func(b *testing.B) {
@@ -77,6 +93,14 @@ func BenchmarkAddGet(b *testing.B) {
 			name: "channel",
 			s:    newChannelStore(),
 		},
+		{
+			name: "mutex",
+			s:    newMutexStore(),
+		},
+		{
+			name: "nolog",
+			s:    newNologStore(),
+		},
 	}
 	for _, bm := range benchmarks {
 		b.Run(bm.name, func(b *testing.B) {
@@ -101,24 +125,40 @@ func BenchmarkGetParallel(b *testing.B) {
 		iterations int
 	}{
 		{
-			name:       "generic",
+			name: "generic",
+			s:    newGenericStore(),
+		},
+		{
+			name: "channel",
+			s:    newChannelStore(),
+		},
+		{
+			name: "mutex",
+			s:    newMutexStore(),
+		},
+		{
+			name: "nolog",
+			s:    newNologStore(),
+		},
+		{
+			name:       "generic overload",
 			s:          newGenericStore(),
 			iterations: 4,
 		},
 		{
-			name:       "channel",
+			name:       "channel overload",
 			s:          newChannelStore(),
 			iterations: 4,
 		},
 		{
-			name:       "generic long",
-			s:          newGenericStore(),
-			iterations: 64,
+			name:       "mutex overload",
+			s:          newMutexStore(),
+			iterations: 4,
 		},
 		{
-			name:       "channel long",
-			s:          newChannelStore(),
-			iterations: 64,
+			name:       "nolog overload",
+			s:          newNologStore(),
+			iterations: 4,
 		},
 	}
 	for _, bm := range benchmarks {
@@ -143,24 +183,40 @@ func BenchmarkAddParallel(b *testing.B) {
 		iterations int
 	}{
 		{
-			name:       "generic",
+			name: "generic",
+			s:    newGenericStore(),
+		},
+		{
+			name: "channel",
+			s:    newChannelStore(),
+		},
+		{
+			name: "mutex",
+			s:    newMutexStore(),
+		},
+		{
+			name: "nolog",
+			s:    newNologStore(),
+		},
+		{
+			name:       "generic overload",
 			s:          newGenericStore(),
 			iterations: 4,
 		},
 		{
-			name:       "channel",
+			name:       "channel overload",
 			s:          newChannelStore(),
 			iterations: 4,
 		},
 		{
-			name:       "generic long",
-			s:          newGenericStore(),
-			iterations: 64,
+			name:       "mutex overload",
+			s:          newMutexStore(),
+			iterations: 4,
 		},
 		{
-			name:       "channel long",
-			s:          newChannelStore(),
-			iterations: 64,
+			name:       "nolog overload",
+			s:          newNologStore(),
+			iterations: 4,
 		},
 	}
 	for _, bm := range benchmarks {
@@ -188,24 +244,40 @@ func BenchmarkAddGetParallel(b *testing.B) {
 		iterations int
 	}{
 		{
-			name:       "generic",
+			name: "generic",
+			s:    newGenericStore(),
+		},
+		{
+			name: "channel",
+			s:    newChannelStore(),
+		},
+		{
+			name: "mutex",
+			s:    newMutexStore(),
+		},
+		{
+			name: "nolog",
+			s:    newNologStore(),
+		},
+		{
+			name:       "generic overload",
 			s:          newGenericStore(),
 			iterations: 4,
 		},
 		{
-			name:       "channel",
+			name:       "channel overload",
 			s:          newChannelStore(),
 			iterations: 4,
 		},
 		{
-			name:       "generic long",
-			s:          newGenericStore(),
-			iterations: 64,
+			name:       "mutex overload",
+			s:          newMutexStore(),
+			iterations: 4,
 		},
 		{
-			name:       "channel long",
-			s:          newChannelStore(),
-			iterations: 64,
+			name:       "nolog overload",
+			s:          newNologStore(),
+			iterations: 4,
 		},
 	}
 	for _, bm := range benchmarks {
-- 
GitLab