@@ -17,8 +17,9 @@ import (
17
17
18
18
// Store contains Metrics.
19
19
type Store struct {
20
- sync.RWMutex
21
- Metrics map [string ][]* Metric
20
+ SearchMu sync.RWMutex // read for iterate and insert, write for delete
21
+ InsertMu sync.Mutex // locked for insert and delete, unlocked for iterate
22
+ Metrics map [string ][]* Metric
22
23
}
23
24
24
25
// NewStore returns a new metric Store.
@@ -30,13 +31,15 @@ func NewStore() (s *Store) {
30
31
31
32
// Add is used to add one metric to the Store.
32
33
func (s * Store ) Add (m * Metric ) error {
33
- s .Lock ()
34
- defer s .Unlock ()
34
+ s .InsertMu .Lock ()
35
+ defer s .InsertMu .Unlock ()
36
+ s .SearchMu .RLock ()
35
37
glog .V (1 ).Infof ("Adding a new metric %v" , m )
36
38
dupeIndex := - 1
37
39
if len (s .Metrics [m .Name ]) > 0 {
38
40
t := s .Metrics [m .Name ][0 ].Kind
39
41
if m .Kind != t {
42
+ s .SearchMu .RUnlock ()
40
43
return errors .Errorf ("Metric %s has different kind %v to existing %v." , m .Name , m .Kind , t )
41
44
}
42
45
@@ -77,25 +80,31 @@ func (s *Store) Add(m *Metric) error {
77
80
}
78
81
}
79
82
}
83
+ s .SearchMu .RUnlock ()
80
84
85
+ // We're in modify mode now so lock out search
86
+ s .SearchMu .Lock ()
81
87
s .Metrics [m .Name ] = append (s .Metrics [m .Name ], m )
82
88
if dupeIndex >= 0 {
83
89
s .Metrics [m .Name ] = append (s .Metrics [m .Name ][0 :dupeIndex ], s .Metrics [m .Name ][dupeIndex + 1 :]... )
84
90
}
91
+ s .SearchMu .Unlock ()
85
92
return nil
86
93
}
87
94
88
95
// ClearMetrics empties the store of all metrics.
89
96
func (s * Store ) ClearMetrics () {
90
- s .Lock ()
91
- defer s .Unlock ()
97
+ s .InsertMu .Lock ()
98
+ defer s .InsertMu .Unlock ()
99
+ s .SearchMu .Lock ()
100
+ defer s .SearchMu .Unlock ()
92
101
s .Metrics = make (map [string ][]* Metric )
93
102
}
94
103
95
104
// MarshalJSON returns a JSON byte string representing the Store.
96
105
func (s * Store ) MarshalJSON () (b []byte , err error ) {
97
- s .Lock ()
98
- defer s .Unlock ()
106
+ s .SearchMu . RLock ()
107
+ defer s .SearchMu . RUnlock ()
99
108
ms := make ([]* Metric , 0 )
100
109
for _ , ml := range s .Metrics {
101
110
ms = append (ms , ml ... )
@@ -107,8 +116,8 @@ func (s *Store) MarshalJSON() (b []byte, err error) {
107
116
// for expiry, and removing them if their expiration time has passed.
108
117
func (s * Store ) Gc () error {
109
118
glog .Info ("Running Store.Expire()" )
110
- s .Lock ()
111
- defer s .Unlock ()
119
+ s .SearchMu . RLock ()
120
+ defer s .SearchMu . RUnlock ()
112
121
now := time .Now ()
113
122
for _ , ml := range s .Metrics {
114
123
for _ , m := range ml {
@@ -154,9 +163,9 @@ func (s *Store) StartGcLoop(ctx context.Context, duration time.Duration) {
154
163
// WriteMetrics dumps the current state of the metrics store in JSON format to
155
164
// the io.Writer.
156
165
func (s * Store ) WriteMetrics (w io.Writer ) error {
157
- s .RLock ()
166
+ s .SearchMu . RLock ()
158
167
b , err := json .MarshalIndent (s .Metrics , "" , " " )
159
- s .RUnlock ()
168
+ s .SearchMu . RUnlock ()
160
169
if err != nil {
161
170
return errors .Wrap (err , "failed to marshal metrics into json" )
162
171
}
0 commit comments