Skip to content

Commit

Permalink
Emit expire code and execute in VM.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaqx0r committed Oct 15, 2018
1 parent 5b56081 commit c1c735e
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 19 deletions.
17 changes: 15 additions & 2 deletions metrics/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func newMetric(len int) *Metric {
LabelValues: make([]*LabelValue, 0)}
}

func (m *Metric) findLabelValueOrNil(labelvalues []string) *LabelValue {
func (m *Metric) FindLabelValueOrNil(labelvalues []string) *LabelValue {
Loop:
for i, lv := range m.LabelValues {
for j := 0; j < len(lv.Labels); j++ {
Expand All @@ -127,7 +127,7 @@ func (m *Metric) GetDatum(labelvalues ...string) (d datum.Datum, err error) {
}
m.Lock()
defer m.Unlock()
if lv := m.findLabelValueOrNil(labelvalues); lv != nil {
if lv := m.FindLabelValueOrNil(labelvalues); lv != nil {
d = lv.Value
} else {
switch m.Type {
Expand Down Expand Up @@ -163,6 +163,19 @@ Loop:
return nil
}

func (m *Metric) ExpireDatum(expiry time.Duration, labelvalues ...string) error {
if len(labelvalues) != len(m.Keys) {
return errors.Errorf("Label values requested (%q) not same length as keys for metric %q", labelvalues, m)
}
m.Lock()
defer m.Unlock()
if lv := m.FindLabelValueOrNil(labelvalues); lv != nil {
lv.Expiry = expiry
return nil
}
return errors.Errorf("No datum for given labelvalues %q", labelvalues)
}

// LabelSet is an object that maps the keys of a Metric to the labels naming a
// Datum, for use when enumerating Datums from a Metric.
type LabelSet struct {
Expand Down
22 changes: 11 additions & 11 deletions metrics/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func TestScalarMetric(t *testing.T) {
t.Errorf("no datum: %s", err)
}
datum.IncIntBy(d, 1, time.Now().UTC())
lv := v.findLabelValueOrNil([]string{})
lv := v.FindLabelValueOrNil([]string{})
if lv == nil {
t.Errorf("couldn't find labelvalue")
}
Expand All @@ -65,21 +65,21 @@ func TestDimensionedMetric(t *testing.T) {
v := NewMetric("test", "prog", Counter, Int, "foo")
d, _ := v.GetDatum("a")
datum.IncIntBy(d, 1, time.Now().UTC())
if v.findLabelValueOrNil([]string{"a"}).Value.ValueString() != "1" {
if v.FindLabelValueOrNil([]string{"a"}).Value.ValueString() != "1" {
t.Errorf("fail")
}

v = NewMetric("test", "prog", Counter, Int, "foo", "bar")
d, _ = v.GetDatum("a", "b")
datum.IncIntBy(d, 1, time.Now().UTC())
if v.findLabelValueOrNil([]string{"a", "b"}).Value.ValueString() != "1" {
if v.FindLabelValueOrNil([]string{"a", "b"}).Value.ValueString() != "1" {
t.Errorf("fail")
}

v = NewMetric("test", "prog", Counter, Int, "foo", "bar", "quux")
d, _ = v.GetDatum("a", "b", "c")
datum.IncIntBy(d, 1, time.Now().UTC())
if v.findLabelValueOrNil([]string{"a", "b", "c"}).Value.ValueString() != "1" {
if v.FindLabelValueOrNil([]string{"a", "b", "c"}).Value.ValueString() != "1" {
t.Errorf("fail")
}
}
Expand Down Expand Up @@ -124,25 +124,25 @@ func TestEmitLabelSet(t *testing.T) {

func TestFindLabelValueOrNil(t *testing.T) {
m0 := NewMetric("foo", "prog", Counter, Int)
if r0 := m0.findLabelValueOrNil([]string{}); r0 != nil {
if r0 := m0.FindLabelValueOrNil([]string{}); r0 != nil {
t.Errorf("m0 should be nil: %v", r0)
}
d, err := m0.GetDatum()
if err != nil {
t.Errorf("Bad datum %v: %v\n", d, err)
}
if r1 := m0.findLabelValueOrNil([]string{}); r1 == nil {
if r1 := m0.FindLabelValueOrNil([]string{}); r1 == nil {
t.Errorf("m0 should not be nil: %v", r1)
}
m1 := NewMetric("bar", "prog", Counter, Int, "a")
d1, err1 := m1.GetDatum("1")
if err1 != nil {
t.Errorf("err1 %v: %v\n", d1, err1)
}
if r2 := m1.findLabelValueOrNil([]string{"0"}); r2 != nil {
if r2 := m1.FindLabelValueOrNil([]string{"0"}); r2 != nil {
t.Errorf("r2 should be nil")
}
if r3 := m1.findLabelValueOrNil([]string{"1"}); r3 == nil {
if r3 := m1.FindLabelValueOrNil([]string{"1"}); r3 == nil {
t.Errorf("r3 should be non nil")
}
}
Expand Down Expand Up @@ -220,7 +220,7 @@ func TestTimer(t *testing.T) {
}
d, _ := m.GetDatum()
datum.IncIntBy(d, 1, time.Now().UTC())
lv := m.findLabelValueOrNil([]string{})
lv := m.FindLabelValueOrNil([]string{})
if lv == nil {
t.Errorf("couldn't find labelvalue")
}
Expand All @@ -239,15 +239,15 @@ func TestRemoveMetricLabelValue(t *testing.T) {
if e != nil {
t.Errorf("Getdatum failed: %s", e)
}
lv := m.findLabelValueOrNil([]string{"a", "a", "a"})
lv := m.FindLabelValueOrNil([]string{"a", "a", "a"})
if lv == nil {
t.Errorf("coidln't find labelvalue")
}
e = m.RemoveDatum("a", "a", "a")
if e != nil {
t.Errorf("couldn't remove datum: %s", e)
}
lv = m.findLabelValueOrNil([]string{"a", "a", "a"})
lv = m.FindLabelValueOrNil([]string{"a", "a", "a"})
if lv != nil {
t.Errorf("label value still exists")
}
Expand Down
8 changes: 4 additions & 4 deletions metrics/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func TestExpireMetric(t *testing.T) {
t.Error(err)
}
datum.SetInt(d, 1, time.Now().Add(-time.Hour))
lv := m.findLabelValueOrNil([]string{"1", "2", "3"})
lv := m.FindLabelValueOrNil([]string{"1", "2", "3"})
if lv == nil {
t.Errorf("couldn't find lv")
}
Expand All @@ -113,18 +113,18 @@ func TestExpireMetric(t *testing.T) {
t.Error(err)
}
datum.SetInt(d, 1, time.Now().Add(-time.Hour))
lv = m.findLabelValueOrNil([]string{"4", "5", "6"})
lv = m.FindLabelValueOrNil([]string{"4", "5", "6"})
if lv == nil {
t.Errorf("couldn't find lv")
}

s.Expire()
lv = m.findLabelValueOrNil([]string{"1", "2", "3"})
lv = m.FindLabelValueOrNil([]string{"1", "2", "3"})
if lv != nil {
t.Errorf("lv not expired: %#v", lv)
t.Logf("Store: %#v", s)
}
lv = m.findLabelValueOrNil([]string{"4", "5", "6"})
lv = m.FindLabelValueOrNil([]string{"4", "5", "6"})
if lv == nil {
t.Errorf("lv expired")
t.Logf("Store: %#v", s)
Expand Down
3 changes: 2 additions & 1 deletion vm/bytecode.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ const (
cat // string concatenation
setmatched // Set "matched" flag
otherwise // Only match if "matched" flag is false.
del // Pop `operand` keys and metric off stack, and remove the datum at metric[key,...] from memory
del // Pop `operand` keys and metric off stack, and remove the datum at metric[key,...] from memory
expire // Set the expiry duration of a datum, perfoming the same as del but after the expiry time passes.

// Floating point ops
fadd
Expand Down
6 changes: 6 additions & 0 deletions vm/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,16 @@ func (c *codegen) VisitBefore(node astNode) Visitor {
c.emit(instr{op: otherwise})

case *delNode:
if n.expiry > 0 {
c.emit(instr{push, n.expiry})
}
Walk(c, n.n)
// overwrite the dload instruction
pc := c.pc()
c.obj.prog[pc].op = del
if n.expiry > 0 {
c.obj.prog[pc].op = expire
}

case *binaryExprNode:
switch n.op {
Expand Down
11 changes: 11 additions & 0 deletions vm/codegen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package vm
import (
"strings"
"testing"
"time"

go_cmp "github.com/google/go-cmp/cmp"
)
Expand Down Expand Up @@ -383,6 +384,16 @@ del a["string"]
{mload, 0},
{del, 1}},
},
{"del after", `
counter a by b
del a["string"] after 1h
`,
[]instr{
{push, time.Hour},
{str, 0},
{mload, 0},
{expire, 1}},
},
{"types", `
gauge i
gauge f
Expand Down
2 changes: 1 addition & 1 deletion vm/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ foo = 3.14
{"delete after",
`counter foo by bar
/foo/ {
del foo[$1] after 7d
del foo[$1] after 168h
}`},

{"getfilename", `
Expand Down
11 changes: 11 additions & 0 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,17 @@ func (v *VM) execute(t *thread, i instr) {
v.errorf("del (RemoveDatum) failed: %s", err)
}

case expire:
m := t.Pop().(*metrics.Metric)
index := i.opnd.(int)
keys := make([]string, index)
for j := index - 1; j >= 0; j-- {
s := t.Pop().(string)
keys[j] = s
}
expiry := t.Pop().(time.Duration)
m.ExpireDatum(expiry, keys...)

case tolower:
// Lowercase a string from TOS, and push result back.
s := t.Pop().(string)
Expand Down
25 changes: 25 additions & 0 deletions vm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,3 +797,28 @@ func TestDatumFetchInstrs(t *testing.T) {
}
}
}

func TestDeleteInstrs(t *testing.T) {
var m []*metrics.Metric
m = append(m,
metrics.NewMetric("a", "tst", metrics.Counter, metrics.Int, "a"),
)

m[0].GetDatum("z")

v := makeVM(instr{expire, 1}, m)
v.t.Push(time.Hour)
v.t.Push("z")
v.t.Push(m[0])
v.execute(v.t, v.prog[0])
if v.terminate {
t.Fatalf("executtion failed, see info log")
}
lv := m[0].FindLabelValueOrNil([]string{"z"})
if lv == nil {
t.Fatalf("couldbn;t find label value in metric %#v", m[0])
}
if lv.Expiry != time.Hour {
t.Fatalf("Expiry not correct, is %v", lv.Expiry)
}
}

0 comments on commit c1c735e

Please sign in to comment.