Skip to content

Commit 21ca39e

Browse files
authored
refactor(timer): replace raw strings by timer.Key for futur use (#121)
Introduction a new `timer.Key` type to better distinguish timer keys from the rest Also remove a useless condition on `timer.NewNode` that will make testing the new API easier
1 parent fb26dc8 commit 21ca39e

File tree

7 files changed

+32
-36
lines changed

7 files changed

+32
-36
lines changed

metrics.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"strings"
1010
"sync"
1111
"time"
12+
13+
"github.com/DataDog/go-libddwaf/v4/timer"
1214
)
1315

1416
// Stats stores the metrics collected by the WAF.
@@ -126,15 +128,15 @@ func (metrics *metricsStore) timers() map[string]time.Duration {
126128
}
127129

128130
// merge merges the current metrics with new ones
129-
func (metrics *metricsStore) merge(scope Scope, other map[string]time.Duration) {
131+
func (metrics *metricsStore) merge(scope Scope, other map[timer.Key]time.Duration) {
130132
metrics.mutex.Lock()
131133
defer metrics.mutex.Unlock()
132134
if metrics.data == nil {
133135
metrics.data = make(map[metricKey]time.Duration, 5)
134136
}
135137

136138
for component, val := range other {
137-
key := metricKey{scope, component}
139+
key := metricKey{scope, string(component)}
138140
prev, ok := metrics.data[key]
139141
if !ok {
140142
prev = 0

timer/base_timer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type baseTimer struct {
2626
parent NodeTimer
2727

2828
// componentName is the name of the component of the timer. It is used to store the time spent in the component and to propagate the stop of the timer to the parent timer.
29-
componentName string
29+
componentName Key
3030

3131
// spent is the time spent on the timer, set after calling stop
3232
spent time.Duration

timer/component.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import (
1111

1212
// components store the data shared between child timers of the same component name
1313
type components struct {
14-
lookup map[string]*atomic.Int64
14+
lookup map[Key]*atomic.Int64
1515
storage []atomic.Int64
1616
}
1717

18-
func newComponents(names []string) components {
19-
lookup := make(map[string]*atomic.Int64, len(names))
18+
func newComponents(names []Key) components {
19+
lookup := make(map[Key]*atomic.Int64, len(names))
2020
storage := make([]atomic.Int64, len(names))
2121
for i, name := range names {
2222
lookup[name] = &storage[i]

timer/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type DynamicBudgetFunc func(timer NodeTimer) time.Duration
2626
type config struct {
2727
dynamicBudget DynamicBudgetFunc
2828
// components store all the components of the timer
29-
components []string
29+
components []Key
3030
// budget is the time budget for the timer
3131
budget time.Duration
3232
}
@@ -79,7 +79,7 @@ func WithInheritedSumBudget() Option {
7979
}
8080

8181
// WithComponents is an Option that adds multiple components to the components list
82-
func WithComponents(components ...string) Option {
82+
func WithComponents(components ...Key) Option {
8383
return func(c *config) {
8484
c.components = append(c.components, components...)
8585
}

timer/node_timer.go

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ func NewTreeTimer(options ...Option) (NodeTimer, error) {
2626
return nil, errors.New("root timer cannot inherit parent budget, please provide a budget using timer.WithBudget() or timer.WithUnlimitedBudget()")
2727
}
2828

29-
if len(config.components) == 0 {
30-
return nil, errors.New("NewTreeTimer: tree timer must have at least one component, otherwise use NewTimer()")
31-
}
32-
3329
return &nodeTimer{
3430
baseTimer: baseTimer{
3531
config: config,
@@ -39,7 +35,7 @@ func NewTreeTimer(options ...Option) (NodeTimer, error) {
3935
}, nil
4036
}
4137

42-
func (timer *nodeTimer) NewNode(name string, options ...Option) (NodeTimer, error) {
38+
func (timer *nodeTimer) NewNode(name Key, options ...Option) (NodeTimer, error) {
4339
config := newConfig(options...)
4440
if len(config.components) == 0 {
4541
return nil, errors.New("NewNode: node timer must have at least one component, otherwise use NewLeaf()")
@@ -61,7 +57,7 @@ func (timer *nodeTimer) NewNode(name string, options ...Option) (NodeTimer, erro
6157
}, nil
6258
}
6359

64-
func (timer *nodeTimer) NewLeaf(name string, options ...Option) (Timer, error) {
60+
func (timer *nodeTimer) NewLeaf(name Key, options ...Option) (Timer, error) {
6561
config := newConfig(options...)
6662
if len(config.components) != 0 {
6763
return nil, errors.New("NewLeaf: leaf timer cannot have components, otherwise use NewNode()")
@@ -80,7 +76,7 @@ func (timer *nodeTimer) NewLeaf(name string, options ...Option) (Timer, error) {
8076
}, nil
8177
}
8278

83-
func (timer *nodeTimer) MustLeaf(name string, options ...Option) Timer {
79+
func (timer *nodeTimer) MustLeaf(name Key, options ...Option) Timer {
8480
leaf, err := timer.NewLeaf(name, options...)
8581
if err != nil {
8682
panic(err)
@@ -90,16 +86,11 @@ func (timer *nodeTimer) MustLeaf(name string, options ...Option) Timer {
9086

9187
func (timer *nodeTimer) childStarted() {}
9288

93-
func (timer *nodeTimer) childStopped(componentName string, duration time.Duration) {
89+
func (timer *nodeTimer) childStopped(componentName Key, duration time.Duration) {
9490
timer.components.lookup[componentName].Add(int64(duration))
95-
if timer.parent == nil {
96-
return
97-
}
98-
99-
timer.parent.childStopped(timer.componentName, duration)
10091
}
10192

102-
func (timer *nodeTimer) AddTime(name string, duration time.Duration) {
93+
func (timer *nodeTimer) AddTime(name Key, duration time.Duration) {
10394
value, ok := timer.components.lookup[name]
10495
if !ok {
10596
return
@@ -108,8 +99,8 @@ func (timer *nodeTimer) AddTime(name string, duration time.Duration) {
10899
value.Add(int64(duration))
109100
}
110101

111-
func (timer *nodeTimer) Stats() map[string]time.Duration {
112-
stats := make(map[string]time.Duration, len(timer.components.lookup))
102+
func (timer *nodeTimer) Stats() map[Key]time.Duration {
103+
stats := make(map[Key]time.Duration, len(timer.components.lookup))
113104
for name, component := range timer.components.lookup {
114105
stats[name] = time.Duration(component.Load())
115106
}

timer/timer.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import (
99
"time"
1010
)
1111

12+
// Key is used to key track of each component of a tree timer. It can be used create constants that can be used to identify components in the tree.
13+
type Key string
14+
1215
// Timer is the default interface for all timers. NewTimer will provide you with a Timer.
1316
// Keep in mind that they are NOT thread-safe and once Stop() is called, the Timer cannot be restarted.
1417
type Timer interface {
@@ -83,32 +86,32 @@ type NodeTimer interface {
8386
// A node timer is required to have at least one component. If no component is provided, it will return an error asking you to use NewLeaf instead.
8487
// If no budget is provided, it will inherit the budget from its parent when calling Start().
8588
// NewNode is thread-safe
86-
NewNode(name string, options ...Option) (NodeTimer, error)
89+
NewNode(name Key, options ...Option) (NodeTimer, error)
8790

8891
// NewLeaf creates a new Timer with the given name and options. The given name must match one of the component name of the parent timer.
8992
// A leaf timer is forbidden to have components. If a component is provided, it will return an error asking you to use NewNode instead.
9093
// If no budget is provided, it will inherit the budget from its parent when calling Start().
9194
// NewLeaf is thread-safe
92-
NewLeaf(name string, options ...Option) (Timer, error)
95+
NewLeaf(name Key, options ...Option) (Timer, error)
9396

9497
// MustLeaf creates a new Timer with the given name and options. The given name must match one of the component name of the parent timer.
9598
// MustLeaf wraps a call to NewLeaf but will panic if the error is not nil.
9699
// MustLeaf is thread-safe
97-
MustLeaf(name string, options ...Option) Timer
100+
MustLeaf(name Key, options ...Option) Timer
98101

99102
// AddTime adds the given duration to the component of the timer with the given name.
100103
// AddTime is thread-safe
101-
AddTime(name string, duration time.Duration)
104+
AddTime(name Key, duration time.Duration)
102105

103106
// Stats returns a map of the time spent in each component of the timer.
104107
// Stats is thread-safe
105-
Stats() map[string]time.Duration
108+
Stats() map[Key]time.Duration
106109

107110
// childStarted is used to propagate the start of a child timer to the parent timer through the whole tree.
108111
childStarted()
109112

110113
// childStopped is used to propagate the time spent in a child timer to the parent timer through the whole tree.
111-
childStopped(componentName string, duration time.Duration)
114+
childStopped(componentName Key, duration time.Duration)
112115

113116
// now is a convenience wrapper to swap the time.Now() function for testing and performance purposes.
114117
now() time.Time

timer/timer_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,9 @@ func TestInheritBudget(t *testing.T) {
226226

227227
func TestTree(t *testing.T) {
228228
t.Run("100-leafs", func(t *testing.T) {
229-
components := make([]string, 100)
229+
components := make([]timer.Key, 100)
230230
for i := range components {
231-
components[i] = strconv.Itoa(i)
231+
components[i] = timer.Key(strconv.Itoa(i))
232232
}
233233

234234
rootTimer, err := timer.NewTreeTimer(timer.WithBudget(time.Hour), timer.WithComponents(components...))
@@ -251,9 +251,9 @@ func TestTree(t *testing.T) {
251251
})
252252

253253
t.Run("100-nodes-1-leaf", func(t *testing.T) {
254-
components := make([]string, 100)
254+
components := make([]timer.Key, 100)
255255
for i := range components {
256-
components[i] = strconv.Itoa(i)
256+
components[i] = timer.Key(strconv.Itoa(i))
257257
}
258258

259259
rootTimer, err := timer.NewTreeTimer(timer.WithBudget(time.Hour), timer.WithComponents(components...))
@@ -279,9 +279,9 @@ func TestTree(t *testing.T) {
279279
})
280280

281281
t.Run("100-nodes-100-leaf", func(t *testing.T) {
282-
components := make([]string, 100)
282+
components := make([]timer.Key, 100)
283283
for i := range components {
284-
components[i] = strconv.Itoa(i)
284+
components[i] = timer.Key(strconv.Itoa(i))
285285
}
286286

287287
rootTimer, err := timer.NewTreeTimer(timer.WithBudget(time.Hour), timer.WithComponents(components...))

0 commit comments

Comments
 (0)