Correctly handle empty labels. (#594)

Currently a time series with empty labels is not treated the same
as one with missing labels. Currently this can only come from
ALERTS&ALERT_FOR_STATE so it's unlikely anyone has actually hit it.

Signed-off-by: Brian Brazil <brian.brazil@robustperception.io>
This commit is contained in:
Brian Brazil 2019-05-07 11:00:16 +01:00 committed by GitHub
parent 2ae028114c
commit 6ac81cc7a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 12 deletions

View file

@ -219,6 +219,29 @@ func TestDBAppenderAddRef(t *testing.T) {
}, res) }, res)
} }
func TestAppendEmptyLabelsIgnored(t *testing.T) {
db, delete := openTestDB(t, nil)
defer func() {
testutil.Ok(t, db.Close())
delete()
}()
app1 := db.Appender()
ref1, err := app1.Add(labels.FromStrings("a", "b"), 123, 0)
testutil.Ok(t, err)
// Construct labels manually so there is an empty label.
ref2, err := app1.Add(labels.Labels{labels.Label{"a", "b"}, labels.Label{"c", ""}}, 124, 0)
testutil.Ok(t, err)
// Should be the same series.
testutil.Equals(t, ref1, ref2)
err = app1.Commit()
testutil.Ok(t, err)
}
func TestDeleteSimple(t *testing.T) { func TestDeleteSimple(t *testing.T) {
numSamples := int64(10) numSamples := int64(10)
@ -1580,26 +1603,26 @@ func TestDB_LabelNames(t *testing.T) {
}{ }{
{ {
sampleLabels1: [][2]string{ sampleLabels1: [][2]string{
[2]string{"name1", ""}, [2]string{"name1", "1"},
[2]string{"name3", ""}, [2]string{"name3", "3"},
[2]string{"name2", ""}, [2]string{"name2", "2"},
}, },
sampleLabels2: [][2]string{ sampleLabels2: [][2]string{
[2]string{"name4", ""}, [2]string{"name4", "4"},
[2]string{"name1", ""}, [2]string{"name1", "1"},
}, },
exp1: []string{"name1", "name2", "name3"}, exp1: []string{"name1", "name2", "name3"},
exp2: []string{"name1", "name2", "name3", "name4"}, exp2: []string{"name1", "name2", "name3", "name4"},
}, },
{ {
sampleLabels1: [][2]string{ sampleLabels1: [][2]string{
[2]string{"name2", ""}, [2]string{"name2", "2"},
[2]string{"name1", ""}, [2]string{"name1", "1"},
[2]string{"name2", ""}, [2]string{"name2", "2"},
}, },
sampleLabels2: [][2]string{ sampleLabels2: [][2]string{
[2]string{"name6", ""}, [2]string{"name6", "6"},
[2]string{"name0", ""}, [2]string{"name0", "0"},
}, },
exp1: []string{"name1", "name2"}, exp1: []string{"name1", "name2"},
exp2: []string{"name0", "name1", "name2", "name6"}, exp2: []string{"name0", "name1", "name2", "name6"},

View file

@ -755,6 +755,9 @@ func (a *headAppender) Add(lset labels.Labels, t int64, v float64) (uint64, erro
return 0, ErrOutOfBounds return 0, ErrOutOfBounds
} }
// Ensure no empty labels have gotten through.
lset = lset.WithoutEmpty()
s, created := a.head.getOrCreate(lset.Hash(), lset) s, created := a.head.getOrCreate(lset.Hash(), lset)
if created { if created {
a.series = append(a.series, RefSeries{ a.series = append(a.series, RefSeries{

View file

@ -103,6 +103,23 @@ func (ls Labels) Map() map[string]string {
return m return m
} }
// WithoutEmpty returns the labelset without empty labels.
// May return the same labelset.
func (ls Labels) WithoutEmpty() Labels {
for _, v := range ls {
if v.Value == "" {
els := make(Labels, 0, len(ls)-1)
for _, v := range ls {
if v.Value != "" {
els = append(els, v)
}
}
return els
}
}
return ls
}
// New returns a sorted Labels from the given labels. // New returns a sorted Labels from the given labels.
// The caller has to guarantee that all label names are unique. // The caller has to guarantee that all label names are unique.
func New(ls ...Label) Labels { func New(ls ...Label) Labels {
@ -119,7 +136,9 @@ func New(ls ...Label) Labels {
func FromMap(m map[string]string) Labels { func FromMap(m map[string]string) Labels {
l := make(Labels, 0, len(m)) l := make(Labels, 0, len(m))
for k, v := range m { for k, v := range m {
l = append(l, Label{Name: k, Value: v}) if v != "" {
l = append(l, Label{Name: k, Value: v})
}
} }
sort.Sort(l) sort.Sort(l)
@ -133,7 +152,9 @@ func FromStrings(ss ...string) Labels {
} }
var res Labels var res Labels
for i := 0; i < len(ss); i += 2 { for i := 0; i < len(ss); i += 2 {
res = append(res, Label{Name: ss[i], Value: ss[i+1]}) if ss[i+1] != "" {
res = append(res, Label{Name: ss[i], Value: ss[i+1]})
}
} }
sort.Sort(res) sort.Sort(res)