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