Skip to content

Commit

Permalink
gauge.go: add Inc, Dec and Add methods to Gauge
Browse files Browse the repository at this point in the history
  • Loading branch information
valyala committed Feb 18, 2024
1 parent fdfd428 commit da211e5
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
34 changes: 33 additions & 1 deletion gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
// - foo{bar="baz",aaa="b"}
//
// f must be safe for concurrent calls.
// if f is nil, then it is expected that the gauge value is changed via Gauge.Set() call.
// if f is nil, then it is expected that the gauge value is changed via Set(), Inc(), Dec() and Add() calls.
//
// The returned gauge is safe to use from concurrent goroutines.
//
Expand Down Expand Up @@ -55,6 +55,38 @@ func (g *Gauge) Set(v float64) {
atomic.StoreUint64(&g.valueBits, n)
}

// Inc increments g by 1.
//
// The g must be created with nil callback in order to be able to call this function.
func (g *Gauge) Inc() {
g.Add(1)
}

// Dec decrements g by 1.
//
// The g must be created with nil callback in order to be able to call this function.
func (g *Gauge) Dec() {
g.Add(-1)
}

// Add adds fAdd to g. fAdd may be positive and negative.
//
// The g must be created with nil callback in order to be able to call this function.
func (g *Gauge) Add(fAdd float64) {
if g.f != nil {
panic(fmt.Errorf("cannot call Set on gauge created with non-nil callback"))
}
for {
n := atomic.LoadUint64(&g.valueBits)
f := math.Float64frombits(n)
fNew := f + fAdd
nNew := math.Float64bits(fNew)
if atomic.CompareAndSwapUint64(&g.valueBits, n, nNew) {
break
}
}
}

func (g *Gauge) marshalTo(prefix string, w io.Writer) {
v := g.Get()
if float64(int64(v)) == v {
Expand Down
55 changes: 55 additions & 0 deletions gauge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ func TestGaugeError(t *testing.T) {
g := GetOrCreateGauge("GetOrCreateGauge_nil_callback", func() float64 { return 123 })
g.Set(42)
})
expectPanic(t, "GetOrCreateGauge_Add_non-nil-callback", func() {
g := GetOrCreateGauge("GetOrCreateGauge_nil_callback", func() float64 { return 123 })
g.Add(42)
})
expectPanic(t, "GetOrCreateGauge_Inc_non-nil-callback", func() {
g := GetOrCreateGauge("GetOrCreateGauge_nil_callback", func() float64 { return 123 })
g.Inc()
})
expectPanic(t, "GetOrCreateGauge_Dec_non-nil-callback", func() {
g := GetOrCreateGauge("GetOrCreateGauge_nil_callback", func() float64 { return 123 })
g.Dec()
})
}

func TestGaugeSet(t *testing.T) {
Expand All @@ -29,6 +41,49 @@ func TestGaugeSet(t *testing.T) {
}
}

func TestGaugeIncDec(t *testing.T) {
s := NewSet()
g := s.NewGauge("foo", nil)
if n := g.Get(); n != 0 {
t.Fatalf("unexpected gauge value: %g; expecting 0", n)
}
for i := 1; i <= 100; i++ {
g.Inc()
if n := g.Get(); n != float64(i) {
t.Fatalf("unexpected gauge value %g; expecting %d", n, i)
}
}
for i := 99; i >= 0; i-- {
g.Dec()
if n := g.Get(); n != float64(i) {
t.Fatalf("unexpected gauge value %g; expecting %d", n, i)
}
}
}

func TestGaugeIncDecConcurrenc(t *testing.T) {
s := NewSet()
g := s.NewGauge("foo", nil)

workers := 5
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
for i := 0; i < 100; i++ {
g.Inc()
g.Dec()
}
wg.Done()
}()
}
wg.Wait()

if n := g.Get(); n != 0 {
t.Fatalf("unexpected gauge value %g; want 0", n)
}
}

func TestGaugeSerial(t *testing.T) {
name := "GaugeSerial"
n := 1.23
Expand Down

0 comments on commit da211e5

Please sign in to comment.