|
|
|
|
@ -18,6 +18,7 @@ import ( |
|
|
|
|
"math" |
|
|
|
|
"math/rand" |
|
|
|
|
"os" |
|
|
|
|
"path" |
|
|
|
|
"path/filepath" |
|
|
|
|
"sort" |
|
|
|
|
"testing" |
|
|
|
|
@ -296,94 +297,158 @@ func TestHeadDeleteSeriesWithoutSamples(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestHeadDeleteSimple(t *testing.T) { |
|
|
|
|
numSamples := int64(10) |
|
|
|
|
|
|
|
|
|
head, err := NewHead(nil, nil, nil, 1000) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
defer head.Close() |
|
|
|
|
|
|
|
|
|
app := head.Appender() |
|
|
|
|
|
|
|
|
|
smpls := make([]float64, numSamples) |
|
|
|
|
for i := int64(0); i < numSamples; i++ { |
|
|
|
|
smpls[i] = rand.Float64() |
|
|
|
|
app.Add(labels.Labels{{"a", "b"}}, i, smpls[i]) |
|
|
|
|
buildSmpls := func(s []int64) []sample { |
|
|
|
|
ss := make([]sample, 0, len(s)) |
|
|
|
|
for _, t := range s { |
|
|
|
|
ss = append(ss, sample{t: t, v: float64(t)}) |
|
|
|
|
} |
|
|
|
|
return ss |
|
|
|
|
} |
|
|
|
|
smplsAll := buildSmpls([]int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) |
|
|
|
|
lblDefault := labels.Label{"a", "b"} |
|
|
|
|
|
|
|
|
|
testutil.Ok(t, app.Commit()) |
|
|
|
|
cases := []struct { |
|
|
|
|
intervals Intervals |
|
|
|
|
remaint []int64 |
|
|
|
|
dranges Intervals |
|
|
|
|
smplsExp []sample |
|
|
|
|
}{ |
|
|
|
|
{ |
|
|
|
|
intervals: Intervals{{0, 3}}, |
|
|
|
|
remaint: []int64{4, 5, 6, 7, 8, 9}, |
|
|
|
|
dranges: Intervals{{0, 3}}, |
|
|
|
|
smplsExp: buildSmpls([]int64{4, 5, 6, 7, 8, 9}), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
intervals: Intervals{{1, 3}}, |
|
|
|
|
remaint: []int64{0, 4, 5, 6, 7, 8, 9}, |
|
|
|
|
dranges: Intervals{{1, 3}}, |
|
|
|
|
smplsExp: buildSmpls([]int64{0, 4, 5, 6, 7, 8, 9}), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
intervals: Intervals{{1, 3}, {4, 7}}, |
|
|
|
|
remaint: []int64{0, 8, 9}, |
|
|
|
|
dranges: Intervals{{1, 3}, {4, 7}}, |
|
|
|
|
smplsExp: buildSmpls([]int64{0, 8, 9}), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
intervals: Intervals{{1, 3}, {4, 700}}, |
|
|
|
|
remaint: []int64{0}, |
|
|
|
|
dranges: Intervals{{1, 3}, {4, 700}}, |
|
|
|
|
smplsExp: buildSmpls([]int64{0}), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
intervals: Intervals{{0, 9}}, |
|
|
|
|
remaint: []int64{}, |
|
|
|
|
{ // This case is to ensure that labels and symbols are deleted.
|
|
|
|
|
dranges: Intervals{{0, 9}}, |
|
|
|
|
smplsExp: buildSmpls([]int64{}), |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Outer: |
|
|
|
|
for _, c := range cases { |
|
|
|
|
// Reset the tombstones.
|
|
|
|
|
head.tombstones = newMemTombstones() |
|
|
|
|
dir, err := ioutil.TempDir("", "test_wal_reload") |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
defer os.RemoveAll(dir) |
|
|
|
|
|
|
|
|
|
w, err := wal.New(nil, nil, path.Join(dir, "wal")) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
|
|
|
|
|
head, err := NewHead(nil, nil, w, 1000) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
|
|
|
|
|
app := head.Appender() |
|
|
|
|
for _, smpl := range smplsAll { |
|
|
|
|
_, err = app.Add(labels.Labels{lblDefault}, smpl.t, smpl.v) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
testutil.Ok(t, app.Commit()) |
|
|
|
|
|
|
|
|
|
// Delete the ranges.
|
|
|
|
|
for _, r := range c.intervals { |
|
|
|
|
testutil.Ok(t, head.Delete(r.Mint, r.Maxt, labels.NewEqualMatcher("a", "b"))) |
|
|
|
|
for _, r := range c.dranges { |
|
|
|
|
testutil.Ok(t, head.Delete(r.Mint, r.Maxt, labels.NewEqualMatcher(lblDefault.Name, lblDefault.Value))) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Compare the result.
|
|
|
|
|
q, err := NewBlockQuerier(head, head.MinTime(), head.MaxTime()) |
|
|
|
|
// Compare the samples for both heads - before and after the reload.
|
|
|
|
|
reloadedW, err := wal.New(nil, nil, w.Dir()) // Use a new wal to ensure deleted samples are gone even after a reload.
|
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
res, err := q.Select(labels.NewEqualMatcher("a", "b")) |
|
|
|
|
reloadedHead, err := NewHead(nil, nil, reloadedW, 1000) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
testutil.Ok(t, reloadedHead.Init(0)) |
|
|
|
|
for _, h := range []*Head{head, reloadedHead} { |
|
|
|
|
indexr, err := h.Index() |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
// Use an emptyTombstoneReader explicitly to get all the samples.
|
|
|
|
|
css, err := LookupChunkSeries(indexr, emptyTombstoneReader, labels.NewEqualMatcher(lblDefault.Name, lblDefault.Value)) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
|
|
|
|
|
expSamples := make([]tsdbutil.Sample, 0, len(c.remaint)) |
|
|
|
|
for _, ts := range c.remaint { |
|
|
|
|
expSamples = append(expSamples, sample{ts, smpls[ts]}) |
|
|
|
|
// Getting the actual samples.
|
|
|
|
|
actSamples := make([]sample, 0) |
|
|
|
|
for css.Next() { |
|
|
|
|
lblsAct, chkMetas, intv := css.At() |
|
|
|
|
testutil.Equals(t, labels.Labels{lblDefault}, lblsAct) |
|
|
|
|
testutil.Equals(t, 0, len(intv)) |
|
|
|
|
|
|
|
|
|
chunkr, err := h.Chunks() |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
for _, meta := range chkMetas { |
|
|
|
|
chk, err := chunkr.Chunk(meta.Ref) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
ii := chk.Iterator() |
|
|
|
|
for ii.Next() { |
|
|
|
|
t, v := ii.At() |
|
|
|
|
actSamples = append(actSamples, sample{t: t, v: v}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
testutil.Ok(t, css.Err()) |
|
|
|
|
testutil.Equals(t, c.smplsExp, actSamples) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
expss := newMockSeriesSet([]Series{ |
|
|
|
|
newSeries(map[string]string{"a": "b"}, expSamples), |
|
|
|
|
// Compare the query results for both heads - before and after the reload.
|
|
|
|
|
expSeriesSet := newMockSeriesSet([]Series{ |
|
|
|
|
newSeries(map[string]string{lblDefault.Name: lblDefault.Value}, func() []tsdbutil.Sample { |
|
|
|
|
ss := make([]tsdbutil.Sample, 0, len(c.smplsExp)) |
|
|
|
|
for _, s := range c.smplsExp { |
|
|
|
|
ss = append(ss, s) |
|
|
|
|
} |
|
|
|
|
return ss |
|
|
|
|
}(), |
|
|
|
|
), |
|
|
|
|
}) |
|
|
|
|
for _, h := range []*Head{head, reloadedHead} { |
|
|
|
|
q, err := NewBlockQuerier(h, h.MinTime(), h.MaxTime()) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
actSeriesSet, err := q.Select(labels.NewEqualMatcher(lblDefault.Name, lblDefault.Value)) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
|
|
|
|
|
if len(expSamples) == 0 { |
|
|
|
|
testutil.Assert(t, res.Next() == false, "") |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
lns, err := q.LabelNames() |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
lvs, err := q.LabelValues(lblDefault.Name) |
|
|
|
|
testutil.Ok(t, err) |
|
|
|
|
// When all samples are deleted we expect that no labels should exist either.
|
|
|
|
|
if len(c.smplsExp) == 0 { |
|
|
|
|
testutil.Equals(t, 0, len(lns)) |
|
|
|
|
testutil.Equals(t, 0, len(lvs)) |
|
|
|
|
testutil.Assert(t, actSeriesSet.Next() == false, "") |
|
|
|
|
testutil.Ok(t, h.Close()) |
|
|
|
|
continue |
|
|
|
|
} else { |
|
|
|
|
testutil.Equals(t, 1, len(lns)) |
|
|
|
|
testutil.Equals(t, 1, len(lvs)) |
|
|
|
|
testutil.Equals(t, lblDefault.Name, lns[0]) |
|
|
|
|
testutil.Equals(t, lblDefault.Value, lvs[0]) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for { |
|
|
|
|
eok, rok := expss.Next(), res.Next() |
|
|
|
|
testutil.Equals(t, eok, rok) |
|
|
|
|
for { |
|
|
|
|
eok, rok := expSeriesSet.Next(), actSeriesSet.Next() |
|
|
|
|
testutil.Equals(t, eok, rok) |
|
|
|
|
|
|
|
|
|
if !eok { |
|
|
|
|
continue Outer |
|
|
|
|
} |
|
|
|
|
sexp := expss.At() |
|
|
|
|
sres := res.At() |
|
|
|
|
if !eok { |
|
|
|
|
testutil.Ok(t, h.Close()) |
|
|
|
|
continue Outer |
|
|
|
|
} |
|
|
|
|
expSeries := expSeriesSet.At() |
|
|
|
|
actSeries := actSeriesSet.At() |
|
|
|
|
|
|
|
|
|
testutil.Equals(t, sexp.Labels(), sres.Labels()) |
|
|
|
|
testutil.Equals(t, expSeries.Labels(), actSeries.Labels()) |
|
|
|
|
|
|
|
|
|
smplExp, errExp := expandSeriesIterator(sexp.Iterator()) |
|
|
|
|
smplRes, errRes := expandSeriesIterator(sres.Iterator()) |
|
|
|
|
smplExp, errExp := expandSeriesIterator(expSeries.Iterator()) |
|
|
|
|
smplRes, errRes := expandSeriesIterator(actSeries.Iterator()) |
|
|
|
|
|
|
|
|
|
testutil.Equals(t, errExp, errRes) |
|
|
|
|
testutil.Equals(t, smplExp, smplRes) |
|
|
|
|
testutil.Equals(t, errExp, errRes) |
|
|
|
|
testutil.Equals(t, smplExp, smplRes) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -524,8 +589,6 @@ func TestDelete_e2e(t *testing.T) { |
|
|
|
|
// TODO: Add Regexp Matchers.
|
|
|
|
|
} |
|
|
|
|
for _, del := range dels { |
|
|
|
|
// Reset the deletes everytime.
|
|
|
|
|
hb.tombstones = newMemTombstones() |
|
|
|
|
for _, r := range del.drange { |
|
|
|
|
testutil.Ok(t, hb.Delete(r.Mint, r.Maxt, del.ms...)) |
|
|
|
|
} |
|
|
|
|
@ -945,4 +1008,5 @@ func TestWalRepair(t *testing.T) { |
|
|
|
|
testutil.Equals(t, test.expRecs, actRec, "Wrong number of intact records") |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|