Skip to content

Commit

Permalink
Merge pull request #3 from PragmaticEngineering/feature/kvstore
Browse files Browse the repository at this point in the history
moving manager options to separate functions to make it easier to adjust if needed in future
splitting and updating tests for benchmarks and tdt
moving the original store implementation to its own package and validation
correcting examples
  • Loading branch information
James Rhoat authored Mar 14, 2024
2 parents 01a43bd + 1a40ea5 commit 0d430b6
Show file tree
Hide file tree
Showing 9 changed files with 354 additions and 213 deletions.
2 changes: 1 addition & 1 deletion examples/basic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
// The contextkey is a string that is used to store and retrieve values from context
// it should be unique to your application
contextKey := "my-unique-context-key"
m := pectx.NewManager(contextKey, &pectx.Store{})
m := pectx.NewManager(contextKey)

ctx := context.Background()

Expand Down
3 changes: 2 additions & 1 deletion examples/duplicates/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"

pectx "github.com/pragmaticengineering/pectx"
)

Expand All @@ -11,7 +12,7 @@ func main() {
// The contextkey is a string that is used to store and retrieve values from context
// it should be unique to your application
contextKey := "my-unique-context-key"
m := pectx.NewManager(contextKey, &pectx.Store{})
m := pectx.NewManager(contextKey)

ctx := context.Background()

Expand Down
41 changes: 37 additions & 4 deletions manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,32 @@ package pectx

import (
"context"

mapStore "github.com/pragmaticengineering/pectx/stores/map"
)

// Store is an interface that defines the methods to store and retrieve data from a Store.
type KVStore interface {
KVGetter
KVSetter
}

// KVGetter is an interface that defines the method to retrieve data from a Store.
type KVGetter interface {
Get(key string) (value string)
ListKeys() []string
}

// KVSetter is an interface that defines the method to store data in a Store.
type KVSetter interface {
Set(key string, value string)
}

type ctxKey string

// ManagerOption is a function that sets some option on the manager.
type ManagerOption func(*Manager)

type Manager struct {
// The context key used to store the data in the context.
// This is to avoid collisions with other packages.
Expand All @@ -14,12 +36,24 @@ type Manager struct {
store KVStore
}

// WithStore changes the store used by the manager.
func WithStore(store KVStore) ManagerOption {
return func(m *Manager) {
m.store = store
}
}

// NewManager creates a new manager with the given context key.
func NewManager(uniqueKey string, store KVStore) *Manager {
return &Manager{
func NewManager(uniqueKey string, opts ...ManagerOption) *Manager {
m := &Manager{
ctxKey: ctxKey(uniqueKey),
store: store,
store: &mapStore.Map{},
}
for _, opt := range opts {
opt(m)
}

return m
}

// Get retrieves the values from the context.
Expand Down Expand Up @@ -51,7 +85,6 @@ func (m *Manager) Set(ctx context.Context, keyValues map[string]string) context.
// GetKeysAndValues retrieves the keys and values from the context.
// if the context is empty, it returns an empty slice.
func (m *Manager) GetKeysAndValues(ctx context.Context) []string {

fields, ok := m.Get(ctx)
if !ok {
return []string{}
Expand Down
163 changes: 163 additions & 0 deletions manager_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package pectx_test

import (
"context"
"fmt"
"testing"

"github.com/pragmaticengineering/pectx"
)

func helperFields(amount int) map[string]string {

store := map[string]string{}
for i := 0; i < amount; i++ {
key := fmt.Sprintf("k%d", i)
store[key] = fmt.Sprintf("v%d", i)

}
return store
}

func BenchmarkManager_Set(b *testing.B) {
var contextKey = "test123123123"

testCases := []struct {
name string
fields map[string]string
mgr *pectx.Manager
ctx context.Context
}{
{
name: "manager with 1 field",
fields: helperFields(1),
mgr: pectx.NewManager(contextKey),
ctx: context.Background(),
},
{
name: "manager with 10 fields",
fields: helperFields(10),
mgr: pectx.NewManager(contextKey),
ctx: context.Background(),
},
{
name: "manager with 100 fields",
fields: helperFields(100),
mgr: pectx.NewManager(contextKey),
ctx: context.Background(),
},
}

for _, tc := range testCases {
b.Run(tc.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
tc.mgr.Set(tc.ctx, tc.fields)
}
})
}
}

func helperFieldsGet(amount int) (context.Context, *pectx.Manager) {
ctx := context.Background()
m := pectx.NewManager(contextKey)

m.Set(ctx, helperFields(amount))

return ctx, m
}

func BenchmarkManager_Get(b *testing.B) {
testCases := []struct {
name string
amount int
}{
{
name: "context with 1 field",
amount: 1,
},
{
name: "context with 10 fields",
amount: 10,
},
{
name: "context with 100 fields",
amount: 100,
},
}

for _, tc := range testCases {
b.Run(tc.name, func(b *testing.B) {
ctx, m := helperFieldsGet(tc.amount)
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Get(ctx)
}
})
}
}

func BenchmarkManager_GetKeysAndValues(b *testing.B) {
testCases := []struct {
name string
amount int
}{
{
name: "context with 1 field",
amount: 1,
},
{
name: "context with 10 fields",
amount: 10,
},
{
name: "context with 100 fields",
amount: 100,
},
}

for _, tc := range testCases {
b.Run(tc.name, func(b *testing.B) {
ctx, m := helperFieldsGet(tc.amount)
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.GetKeysAndValues(ctx)
}
})
}
}

func BenchmarkKeysAndValues_forloop(b *testing.B) {
manager := pectx.NewManager(contextKey)

// Define test cases
testCases := []struct {
name string
data map[string]string
}{
{
name: "Set 1 key-value pair",
data: map[string]string{
"key1": "value1",
},
},
{
name: "Set 10 key-value pairs",
data: helperFields(10),
},
{
name: "Set 100 key-value pairs",
data: helperFields(100),
},
}

for _, tc := range testCases {
testcase := tc
b.Run(testcase.name, func(b *testing.B) {
ctx := manager.Set(context.Background(), testcase.data)
b.ResetTimer()
for i := 0; i < b.N; i++ {
manager.GetKeysAndValues(ctx)
}
})
}
}
Loading

0 comments on commit 0d430b6

Please sign in to comment.