Skip to content

Commit 99c0716

Browse files
committed
sqlstats: use Go 1.19 atomics, round MeanDuration more
And split the QueryStats type into an internal accounting half (with the atomics) and a public half (with natural types). Updates tailscale/tailscale#5210 Signed-off-by: Brad Fitzpatrick <[email protected]>
1 parent 1757618 commit 99c0716

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

sqlstats/sqlstats.go

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type Tracer struct {
3838
// in the steady state, a sync.Map would be a faster object
3939
// here.
4040
mu sync.RWMutex
41-
queries map[string]*QueryStats // normalized query -> stats
41+
queries map[string]*queryStats // normalized query -> stats
4242
}
4343

4444
// Reset resets the state of t to its initial conditions.
@@ -101,8 +101,6 @@ func (t *Tracer) done(s *connStats) (why string, readOnly bool) {
101101
type QueryStats struct {
102102
Query string
103103

104-
// When inside the queries map all fields must be accessed as atomics.
105-
106104
// Count represents the number of times this query has been
107105
// executed.
108106
Count int64
@@ -116,8 +114,23 @@ type QueryStats struct {
116114

117115
// MeanDuration represents the average time spent executing the query.
118116
MeanDuration time.Duration
117+
}
118+
119+
// queryStats is the internal stats for a given Query containing
120+
// atomics and updated at runtime.
121+
type queryStats struct {
122+
Query string
119123

120-
// TODO lastErr atomic.Value
124+
// Count represents the number of times this query has been
125+
// executed.
126+
Count atomic.Int64
127+
128+
// Errors represents the number of errors encountered executing
129+
// this query.
130+
Errors atomic.Int64
131+
132+
// TotalDurationNanos represents the accumulated time spent executing the query.
133+
TotalDurationNanos atomic.Int64 // a time.Duration in nanoseconds
121134
}
122135

123136
var rxRemoveInClause = regexp.MustCompile(`(?i)\s+in\s*\((?:\s*\d+\s*(?:,\s*\d+\s*)*)\)`)
@@ -129,7 +142,7 @@ func normalizeQuery(q string) string {
129142
return q
130143
}
131144

132-
func (t *Tracer) queryStats(query string) *QueryStats {
145+
func (t *Tracer) queryStats(query string) *queryStats {
133146
query = normalizeQuery(query)
134147

135148
t.mu.RLock()
@@ -143,11 +156,11 @@ func (t *Tracer) queryStats(query string) *QueryStats {
143156
t.mu.Lock()
144157
defer t.mu.Unlock()
145158
if t.queries == nil {
146-
t.queries = make(map[string]*QueryStats)
159+
t.queries = make(map[string]*queryStats)
147160
}
148161
stats = t.queries[query]
149162
if stats == nil {
150-
stats = &QueryStats{Query: query}
163+
stats = &queryStats{Query: query}
151164
t.queries[query] = stats
152165
}
153166
return stats
@@ -161,15 +174,15 @@ func (t *Tracer) Collect() (rows []*QueryStats) {
161174

162175
rows = make([]*QueryStats, 0, len(t.queries))
163176
for query, s := range t.queries {
164-
row := QueryStats{
177+
row := &QueryStats{
165178
Query: query,
166-
Count: atomic.LoadInt64(&s.Count),
167-
Errors: atomic.LoadInt64(&s.Errors),
168-
TotalDuration: time.Duration(atomic.LoadInt64((*int64)(&s.TotalDuration))),
179+
Count: s.Count.Load(),
180+
Errors: s.Errors.Load(),
181+
TotalDuration: time.Duration(s.TotalDurationNanos.Load()),
169182
}
170183

171184
row.MeanDuration = time.Duration(int64(row.TotalDuration) / row.Count)
172-
rows = append(rows, &row)
185+
rows = append(rows, row)
173186
}
174187
return rows
175188
}
@@ -183,11 +196,11 @@ func (t *Tracer) Query(
183196
) {
184197
stats := t.queryStats(query)
185198

186-
atomic.AddInt64(&stats.Count, 1)
187-
atomic.AddInt64((*int64)(&stats.TotalDuration), int64(duration))
199+
stats.Count.Add(1)
200+
stats.TotalDurationNanos.Add(int64(duration))
188201

189202
if err != nil {
190-
atomic.AddInt64(&stats.Errors, 1)
203+
stats.Errors.Add(1)
191204
}
192205
}
193206

@@ -349,11 +362,15 @@ func (t *Tracer) Handle(w http.ResponseWriter, r *http.Request) {
349362
</tr>
350363
`)
351364
for _, row := range rows {
365+
d := row.MeanDuration.Round(time.Microsecond)
366+
if d > 1*time.Millisecond {
367+
d = d.Round(time.Millisecond)
368+
}
352369
fmt.Fprintf(w, "<tr><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%d</td></tr>\n",
353370
row.Query,
354371
row.Count,
355372
row.TotalDuration.Round(time.Second),
356-
row.MeanDuration.Round(time.Millisecond),
373+
d,
357374
row.Errors,
358375
)
359376
}

0 commit comments

Comments
 (0)