Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
loki/pkg/iter/sample_iterator_test.go

226 lines
5.5 KiB

Improve metric queries by computing samples at the edges. (#2293) * First pass breaking the code appart. Wondering how we're going to achieve fast mutation of labels. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Work in progress. I realize I need hash for deduping lines. going to benchmark somes. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Tested some hash and decided which one to use. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Wip Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Starting working on ingester. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Trying to find a better hash function. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * More hash testing we have a winner. xxhash it is. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Settle on xxhash Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Better params interfacing. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add interface for queryparams for things that exist in both type of params. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add storage sample iterator implementations. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing tests and verifying we don't get collions for the hashing method. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing ingesters tests and refactoring utility function/tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing and testing that stats are still well computed. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing more tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * More engine tests finished. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixes sharding evaluator. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixes more engine tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fix error tests in the engine. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Finish fixing all tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixes a bug where extractor was not passed in correctly. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add notes about upgrade. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Renamed and fix a bug. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add memchunk tests and starting test for sampleIterator. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Test heap sample iterator. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * working on test. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Finishing testing all new iterators. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Making sure all store functions are tested. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Benchmark and verify everything is working well. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Make the linter happy. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * use xxhash v2. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fix a flaky test because of map. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * go.mod. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> Co-authored-by: Edward Welch <edward.welch@grafana.com>
5 years ago
package iter
import (
"context"
"io"
"testing"
"time"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
Improve metric queries by computing samples at the edges. (#2293) * First pass breaking the code appart. Wondering how we're going to achieve fast mutation of labels. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Work in progress. I realize I need hash for deduping lines. going to benchmark somes. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Tested some hash and decided which one to use. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Wip Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Starting working on ingester. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Trying to find a better hash function. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * More hash testing we have a winner. xxhash it is. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Settle on xxhash Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Better params interfacing. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add interface for queryparams for things that exist in both type of params. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add storage sample iterator implementations. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing tests and verifying we don't get collions for the hashing method. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing ingesters tests and refactoring utility function/tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing and testing that stats are still well computed. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixing more tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * More engine tests finished. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixes sharding evaluator. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixes more engine tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fix error tests in the engine. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Finish fixing all tests. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fixes a bug where extractor was not passed in correctly. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add notes about upgrade. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Renamed and fix a bug. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Add memchunk tests and starting test for sampleIterator. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Test heap sample iterator. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * working on test. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Finishing testing all new iterators. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Making sure all store functions are tested. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Benchmark and verify everything is working well. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Make the linter happy. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * use xxhash v2. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * Fix a flaky test because of map. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> * go.mod. Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com> Co-authored-by: Edward Welch <edward.welch@grafana.com>
5 years ago
"github.com/grafana/loki/pkg/logproto"
)
func TestNewPeekingSampleIterator(t *testing.T) {
iter := NewPeekingSampleIterator(NewSeriesIterator(logproto.Series{
Samples: []logproto.Sample{
{
Timestamp: time.Unix(0, 1).UnixNano(),
},
{
Timestamp: time.Unix(0, 2).UnixNano(),
},
{
Timestamp: time.Unix(0, 3).UnixNano(),
},
},
}))
_, peek, ok := iter.Peek()
if peek.Timestamp != 1 {
t.Fatal("wrong peeked time.")
}
if !ok {
t.Fatal("should be ok.")
}
hasNext := iter.Next()
if !hasNext {
t.Fatal("should have next.")
}
if iter.Sample().Timestamp != 1 {
t.Fatal("wrong peeked time.")
}
_, peek, ok = iter.Peek()
if peek.Timestamp != 2 {
t.Fatal("wrong peeked time.")
}
if !ok {
t.Fatal("should be ok.")
}
hasNext = iter.Next()
if !hasNext {
t.Fatal("should have next.")
}
if iter.Sample().Timestamp != 2 {
t.Fatal("wrong peeked time.")
}
_, peek, ok = iter.Peek()
if peek.Timestamp != 3 {
t.Fatal("wrong peeked time.")
}
if !ok {
t.Fatal("should be ok.")
}
hasNext = iter.Next()
if !hasNext {
t.Fatal("should have next.")
}
if iter.Sample().Timestamp != 3 {
t.Fatal("wrong peeked time.")
}
_, _, ok = iter.Peek()
if ok {
t.Fatal("should not be ok.")
}
require.NoError(t, iter.Close())
require.NoError(t, iter.Error())
}
func sample(i int) logproto.Sample {
return logproto.Sample{
Timestamp: int64(i),
Hash: uint64(i),
Value: float64(1),
}
}
var varSeries = logproto.Series{
Labels: `{foo="var"}`,
Samples: []logproto.Sample{
sample(1), sample(2), sample(3),
},
}
var carSeries = logproto.Series{
Labels: `{foo="car"}`,
Samples: []logproto.Sample{
sample(1), sample(2), sample(3),
},
}
func TestNewHeapSampleIterator(t *testing.T) {
it := NewHeapSampleIterator(context.Background(),
[]SampleIterator{
NewSeriesIterator(varSeries),
NewSeriesIterator(carSeries),
NewSeriesIterator(carSeries),
NewSeriesIterator(varSeries),
NewSeriesIterator(carSeries),
NewSeriesIterator(varSeries),
NewSeriesIterator(carSeries),
})
for i := 1; i < 4; i++ {
require.True(t, it.Next(), i)
require.Equal(t, `{foo="car"}`, it.Labels(), i)
require.Equal(t, sample(i), it.Sample(), i)
require.True(t, it.Next(), i)
require.Equal(t, `{foo="var"}`, it.Labels(), i)
require.Equal(t, sample(i), it.Sample(), i)
}
require.False(t, it.Next())
require.NoError(t, it.Error())
require.NoError(t, it.Close())
}
type fakeSampleClient struct {
series [][]logproto.Series
curr int
}
func (f *fakeSampleClient) Recv() (*logproto.SampleQueryResponse, error) {
if f.curr >= len(f.series) {
return nil, io.EOF
}
res := &logproto.SampleQueryResponse{
Series: f.series[f.curr],
}
f.curr++
return res, nil
}
func (fakeSampleClient) Context() context.Context { return context.Background() }
func (fakeSampleClient) CloseSend() error { return nil }
func TestNewSampleQueryClientIterator(t *testing.T) {
it := NewSampleQueryClientIterator(&fakeSampleClient{
series: [][]logproto.Series{
{varSeries},
{carSeries},
},
})
for i := 1; i < 4; i++ {
require.True(t, it.Next(), i)
require.Equal(t, `{foo="var"}`, it.Labels(), i)
require.Equal(t, sample(i), it.Sample(), i)
}
for i := 1; i < 4; i++ {
require.True(t, it.Next(), i)
require.Equal(t, `{foo="car"}`, it.Labels(), i)
require.Equal(t, sample(i), it.Sample(), i)
}
require.False(t, it.Next())
require.NoError(t, it.Error())
require.NoError(t, it.Close())
}
func TestNewNonOverlappingSampleIterator(t *testing.T) {
it := NewNonOverlappingSampleIterator([]SampleIterator{
NewSeriesIterator(varSeries),
NewSeriesIterator(logproto.Series{
Labels: varSeries.Labels,
Samples: []logproto.Sample{sample(4), sample(5)},
}),
}, varSeries.Labels)
for i := 1; i < 6; i++ {
require.True(t, it.Next(), i)
require.Equal(t, `{foo="var"}`, it.Labels(), i)
require.Equal(t, sample(i), it.Sample(), i)
}
require.False(t, it.Next())
require.NoError(t, it.Error())
require.NoError(t, it.Close())
}
func TestReadSampleBatch(t *testing.T) {
res, size, err := ReadSampleBatch(NewSeriesIterator(carSeries), 1)
require.Equal(t, &logproto.SampleQueryResponse{Series: []logproto.Series{{Labels: carSeries.Labels, Samples: []logproto.Sample{sample(1)}}}}, res)
require.Equal(t, uint32(1), size)
require.NoError(t, err)
res, size, err = ReadSampleBatch(NewMultiSeriesIterator(context.Background(), []logproto.Series{carSeries, varSeries}), 100)
require.ElementsMatch(t, []logproto.Series{carSeries, varSeries}, res.Series)
require.Equal(t, uint32(6), size)
require.NoError(t, err)
}
type CloseTestingSmplIterator struct {
closed atomic.Bool
s logproto.Sample
}
func (i *CloseTestingSmplIterator) Next() bool { return true }
func (i *CloseTestingSmplIterator) Sample() logproto.Sample { return i.s }
func (i *CloseTestingSmplIterator) Labels() string { return "" }
func (i *CloseTestingSmplIterator) Error() error { return nil }
func (i *CloseTestingSmplIterator) Close() error {
i.closed.Store(true)
return nil
}
func TestNonOverlappingSampleClose(t *testing.T) {
a, b := &CloseTestingSmplIterator{}, &CloseTestingSmplIterator{}
itr := NewNonOverlappingSampleIterator([]SampleIterator{a, b}, "")
// Ensure both itr.cur and itr.iterators are non nil
itr.Next()
require.NotNil(t, itr.(*nonOverlappingSampleIterator).curr)
itr.Close()
require.Equal(t, true, a.closed.Load())
require.Equal(t, true, b.closed.Load())
}