@ -2,12 +2,15 @@ package storage
import (
"context"
"fmt"
"testing"
"time"
"github.com/grafana/loki/pkg/chunkenc"
"github.com/grafana/loki/pkg/iter"
"github.com/grafana/loki/pkg/logproto"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/stretchr/testify/require"
)
func Test_newBatchChunkIterator ( t * testing . T ) {
@ -18,11 +21,12 @@ func Test_newBatchChunkIterator(t *testing.T) {
matchers string
start , end time . Time
direction logproto . Direction
batchSize int
} {
"forward with overlap" : {
[ ] * chunkenc . LazyChunk {
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
@ -35,7 +39,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( time . Millisecond ) ,
@ -48,7 +52,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( time . Millisecond ) ,
@ -61,7 +65,120 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
{
Timestamp : from . Add ( 4 * time . Millisecond ) ,
Line : "5" ,
} ,
} ,
} ) ,
} ,
[ ] * logproto . Stream {
{
Labels : fooLabels ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
Line : "1" ,
} ,
{
Timestamp : from . Add ( time . Millisecond ) ,
Line : "2" ,
} ,
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} ,
} ,
fooLabelsWithName ,
from , from . Add ( 4 * time . Millisecond ) ,
logproto . FORWARD ,
2 ,
} ,
"forward with overlapping non-continuous entries" : {
[ ] * chunkenc . LazyChunk {
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
Line : "1" ,
} ,
{
Timestamp : from . Add ( time . Millisecond ) ,
Line : "2" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( time . Millisecond ) ,
Line : "2" ,
} ,
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( time . Millisecond ) ,
Line : "2" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
@ -93,14 +210,15 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ,
} ,
fooLabels ,
fooLabelsWithName ,
from , from . Add ( 3 * time . Millisecond ) ,
logproto . FORWARD ,
2 ,
} ,
"backward with overlap" : {
[ ] * chunkenc . LazyChunk {
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
@ -113,7 +231,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( time . Millisecond ) ,
@ -126,7 +244,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( time . Millisecond ) ,
@ -139,7 +257,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
@ -151,11 +269,41 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
{
Timestamp : from . Add ( 4 * time . Millisecond ) ,
Line : "5" ,
} ,
} ,
} ) ,
} ,
[ ] * logproto . Stream {
{
Labels : fooLabels ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
@ -171,14 +319,114 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ,
} ,
fooLabels ,
from , from . Add ( 3 * time . Millisecond ) ,
fooLabelsWithName ,
from , from . Add ( 4 * time . Millisecond ) ,
logproto . BACKWARD ,
2 ,
} ,
"forward without overlap " : {
"backward with overlapping non-continuous entries " : {
[ ] * chunkenc . LazyChunk {
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 0 * time . Millisecond ) ,
Line : "0" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "3" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 1 * time . Millisecond ) ,
Line : "1" ,
} ,
{
Timestamp : from . Add ( 6 * time . Millisecond ) ,
Line : "6" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "2" ,
} ,
{
Timestamp : from . Add ( 5 * time . Millisecond ) ,
Line : "5" ,
} ,
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 4 * time . Millisecond ) ,
Line : "4" ,
} ,
{
Timestamp : from . Add ( 7 * time . Millisecond ) ,
Line : "7" ,
} ,
} ,
} ) ,
} ,
[ ] * logproto . Stream {
{
Labels : fooLabels ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 7 * time . Millisecond ) ,
Line : "7" ,
} ,
{
Timestamp : from . Add ( 6 * time . Millisecond ) ,
Line : "6" ,
} ,
{
Timestamp : from . Add ( 5 * time . Millisecond ) ,
Line : "5" ,
} ,
{
Timestamp : from . Add ( 4 * time . Millisecond ) ,
Line : "4" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "3" ,
} ,
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "2" ,
} ,
{
Timestamp : from . Add ( 1 * time . Millisecond ) ,
Line : "1" ,
} ,
{
Timestamp : from . Add ( 0 * time . Millisecond ) ,
Line : "0" ,
} ,
} ,
} ,
} ,
fooLabelsWithName ,
from , from . Add ( 8 * time . Millisecond ) ,
logproto . BACKWARD ,
2 ,
} ,
"forward without overlap" : {
[ ] * chunkenc . LazyChunk {
newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
@ -191,7 +439,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
@ -200,7 +448,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
@ -228,14 +476,15 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ,
} ,
fooLabels ,
fooLabelsWithName ,
from , from . Add ( 3 * time . Millisecond ) ,
logproto . FORWARD ,
2 ,
} ,
"backward without overlap" : {
[ ] * chunkenc . LazyChunk {
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
@ -248,7 +497,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
@ -257,7 +506,7 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ) ,
newLazyChunk ( logproto . Stream {
Labels : fooLabels ,
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
@ -285,16 +534,17 @@ func Test_newBatchChunkIterator(t *testing.T) {
} ,
} ,
} ,
fooLabels ,
fooLabelsWithName ,
from , from . Add ( 3 * time . Millisecond ) ,
logproto . BACKWARD ,
2 ,
} ,
}
for name , tt := range tests {
tt := tt
t . Run ( name , func ( t * testing . T ) {
it := newBatchChunkIterator ( context . Background ( ) , tt . chunks , 2 , newMatchers ( tt . matchers ) , nil , newQuery ( "" , tt . start , tt . end , tt . direction ) )
it := newBatchChunkIterator ( context . Background ( ) , tt . chunks , tt . batchSize , newMatchers ( tt . matchers ) , nil , newQuery ( "" , tt . start , tt . end , tt . direction ) )
streams , _ , err := iter . ReadBatch ( it , 1000 )
_ = it . Close ( )
if err != nil {
@ -305,5 +555,127 @@ func Test_newBatchChunkIterator(t *testing.T) {
} )
}
}
func TestPartitionOverlappingchunks ( t * testing . T ) {
var (
oneThroughFour = newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from ,
Line : "1" ,
} ,
{
Timestamp : from . Add ( 3 * time . Millisecond ) ,
Line : "4" ,
} ,
} ,
} )
two = newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 1 * time . Millisecond ) ,
Line : "2" ,
} ,
} ,
} )
three = newLazyChunk ( logproto . Stream {
Labels : fooLabelsWithName ,
Entries : [ ] logproto . Entry {
{
Timestamp : from . Add ( 2 * time . Millisecond ) ,
Line : "3" ,
} ,
} ,
} )
)
for i , tc := range [ ] struct {
input [ ] * chunkenc . LazyChunk
expected [ ] [ ] * chunkenc . LazyChunk
} {
{
input : [ ] * chunkenc . LazyChunk {
oneThroughFour ,
two ,
three ,
} ,
expected : [ ] [ ] * chunkenc . LazyChunk {
[ ] * chunkenc . LazyChunk { oneThroughFour } ,
[ ] * chunkenc . LazyChunk { two , three } ,
} ,
} ,
{
input : [ ] * chunkenc . LazyChunk {
two ,
oneThroughFour ,
three ,
} ,
expected : [ ] [ ] * chunkenc . LazyChunk {
[ ] * chunkenc . LazyChunk { oneThroughFour } ,
[ ] * chunkenc . LazyChunk { two , three } ,
} ,
} ,
{
input : [ ] * chunkenc . LazyChunk {
two ,
two ,
three ,
three ,
} ,
expected : [ ] [ ] * chunkenc . LazyChunk {
[ ] * chunkenc . LazyChunk { two , three } ,
[ ] * chunkenc . LazyChunk { two , three } ,
} ,
} ,
} {
t . Run ( fmt . Sprintf ( "%d" , i ) , func ( t * testing . T ) {
out := partitionOverlappingChunks ( tc . input )
require . Equal ( t , tc . expected , out )
} )
}
}
func TestDropLabels ( t * testing . T ) {
for i , tc := range [ ] struct {
ls labels . Labels
drop [ ] string
expected labels . Labels
} {
{
ls : labels . Labels {
labels . Label {
Name : "a" ,
Value : "1" ,
} ,
labels . Label {
Name : "b" ,
Value : "2" ,
} ,
labels . Label {
Name : "c" ,
Value : "3" ,
} ,
} ,
drop : [ ] string { "b" } ,
expected : labels . Labels {
labels . Label {
Name : "a" ,
Value : "1" ,
} ,
labels . Label {
Name : "c" ,
Value : "3" ,
} ,
} ,
} ,
} {
t . Run ( fmt . Sprintf ( "%d" , i ) , func ( t * testing . T ) {
dropped := dropLabels ( tc . ls , tc . drop ... )
require . Equal ( t , tc . expected , dropped )
} )
}
}