From ff77a29b0ae45d9ea8d5cf988e441a8a49db7b3a Mon Sep 17 00:00:00 2001 From: Justin Li Date: Tue, 22 Jul 2014 12:42:56 -0400 Subject: [PATCH] Thread safe, but unsafe --- stats/percentile.go | 24 ++++++++++++++++-------- stats/stats.go | 11 ++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/stats/percentile.go b/stats/percentile.go index 9ca3a4a..534a447 100644 --- a/stats/percentile.go +++ b/stats/percentile.go @@ -3,6 +3,8 @@ package stats import ( "math" "sort" + "sync/atomic" + "unsafe" ) type Percentile struct { @@ -10,17 +12,23 @@ type Percentile struct { samples int64 offset int64 - values []float64 + + values []float64 + value *unsafe.Pointer } func NewPercentile(percentile float64, sampleWindow int) *Percentile { + initial := 0 + ptr := unsafe.Pointer(&initial) + return &Percentile{ percentile: percentile, - values: make([]float64, 0, sampleWindow), + + values: make([]float64, 0, sampleWindow), + value: &ptr, } } -// Not thread safe. func (p *Percentile) AddSample(sample float64) { p.samples++ @@ -55,14 +63,14 @@ func (p *Percentile) AddSample(sample float64) { copy(p.values[idx+1:], p.values[idx:]) p.values[idx] = sample } + + value := p.values[p.index()] + atomic.SwapPointer(p.value, unsafe.Pointer(&value)) } func (p *Percentile) Value() float64 { - if len(p.values) == 0 { - return 0 - } - - return p.values[p.index()] + pointer := atomic.LoadPointer(p.value) + return *(*float64)(pointer) } func (p *Percentile) index() int64 { diff --git a/stats/stats.go b/stats/stats.go index 99d460a..8ea9777 100644 --- a/stats/stats.go +++ b/stats/stats.go @@ -106,6 +106,10 @@ func (s *Stats) RecordEvent(event int) { s.events <- event } +func (s *Stats) RecordTiming(event int, duration time.Duration) { + // s.timingEvents <- event +} + func (s *Stats) handleEvents() { for event := range s.events { switch event { @@ -178,7 +182,12 @@ func (s *Stats) handleEvents() { } } -// RecordEvent broadcasts an event to the default stats tracking. +// RecordEvent broadcasts an event to the default stats queue. func RecordEvent(event int) { DefaultStats.RecordEvent(event) } + +// RecordTiming broadcasts a timing event to the default stats queue. +func RecordTiming(event int, duration time.Duration) { + DefaultStats.RecordTiming(event, duration) +}