@ -685,12 +685,14 @@ func TestBlockQuerierDelete(t *testing.T) {
type fakeChunksReader struct {
ChunkReader
chks map [ chunks . ChunkRef ] chunkenc . Chunk
chks map [ chunks . ChunkRef ] chunkenc . Chunk
iterables map [ chunks . ChunkRef ] chunkenc . Iterable
}
func createFakeReaderAndNotPopulatedChunks ( s ... [ ] chunks . Sample ) ( * fakeChunksReader , [ ] chunks . Meta ) {
f := & fakeChunksReader {
chks : map [ chunks . ChunkRef ] chunkenc . Chunk { } ,
chks : map [ chunks . ChunkRef ] chunkenc . Chunk { } ,
iterables : map [ chunks . ChunkRef ] chunkenc . Iterable { } ,
}
chks := make ( [ ] chunks . Meta , 0 , len ( s ) )
@ -707,21 +709,102 @@ func createFakeReaderAndNotPopulatedChunks(s ...[]chunks.Sample) (*fakeChunksRea
return f , chks
}
func ( r * fakeChunksReader ) Chunk ( meta chunks . Meta ) ( chunkenc . Chunk , error ) {
chk , ok := r . chks [ meta . Ref ]
if ! ok {
return nil , fmt . Errorf ( "chunk not found at ref %v" , meta . Ref )
// Samples in each slice are assumed to be sorted.
func createFakeReaderAndIterables ( s ... [ ] chunks . Sample ) ( * fakeChunksReader , [ ] chunks . Meta ) {
f := & fakeChunksReader {
chks : map [ chunks . ChunkRef ] chunkenc . Chunk { } ,
iterables : map [ chunks . ChunkRef ] chunkenc . Iterable { } ,
}
chks := make ( [ ] chunks . Meta , 0 , len ( s ) )
for ref , samples := range s {
f . iterables [ chunks . ChunkRef ( ref ) ] = & mockIterable { s : samples }
var minTime , maxTime int64
if len ( samples ) > 0 {
minTime = samples [ 0 ] . T ( )
maxTime = samples [ len ( samples ) - 1 ] . T ( )
}
chks = append ( chks , chunks . Meta {
Ref : chunks . ChunkRef ( ref ) ,
MinTime : minTime ,
MaxTime : maxTime ,
} )
}
return f , chks
}
func ( r * fakeChunksReader ) ChunkOrIterable ( meta chunks . Meta ) ( chunkenc . Chunk , chunkenc . Iterable , error ) {
if chk , ok := r . chks [ meta . Ref ] ; ok {
return chk , nil , nil
}
if it , ok := r . iterables [ meta . Ref ] ; ok {
return nil , it , nil
}
return nil , nil , fmt . Errorf ( "chunk or iterable not found at ref %v" , meta . Ref )
}
type mockIterable struct {
s [ ] chunks . Sample
}
func ( it * mockIterable ) Iterator ( chunkenc . Iterator ) chunkenc . Iterator {
return & mockSampleIterator {
s : it . s ,
idx : - 1 ,
}
}
type mockSampleIterator struct {
s [ ] chunks . Sample
idx int
}
func ( it * mockSampleIterator ) Seek ( t int64 ) chunkenc . ValueType {
for ; it . idx < len ( it . s ) ; it . idx ++ {
if it . idx != - 1 && it . s [ it . idx ] . T ( ) >= t {
return it . s [ it . idx ] . Type ( )
}
}
return chk , nil
return chunkenc . ValNone
}
func ( it * mockSampleIterator ) At ( ) ( int64 , float64 ) {
return it . s [ it . idx ] . T ( ) , it . s [ it . idx ] . F ( )
}
func ( it * mockSampleIterator ) AtHistogram ( ) ( int64 , * histogram . Histogram ) {
return it . s [ it . idx ] . T ( ) , it . s [ it . idx ] . H ( )
}
func ( it * mockSampleIterator ) AtFloatHistogram ( ) ( int64 , * histogram . FloatHistogram ) {
return it . s [ it . idx ] . T ( ) , it . s [ it . idx ] . FH ( )
}
func ( it * mockSampleIterator ) AtT ( ) int64 {
return it . s [ it . idx ] . T ( )
}
func ( it * mockSampleIterator ) Next ( ) chunkenc . ValueType {
if it . idx < len ( it . s ) - 1 {
it . idx ++
return it . s [ it . idx ] . Type ( )
}
return chunkenc . ValNone
}
func ( it * mockSampleIterator ) Err ( ) error { return nil }
func TestPopulateWithTombSeriesIterators ( t * testing . T ) {
type minMaxTimes struct {
minTime , maxTime int64
}
cases := [ ] struct {
name string
chks [ ] [ ] chunks . Sample
name string
sample s [ ] [ ] chunks . Sample
expected [ ] chunks . Sample
expectedChks [ ] chunks . Meta
@ -732,23 +815,38 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
// Seek being zero means do not test seek.
seek int64
seekSuccess bool
// Set this to true if a sample slice will form multiple chunks.
skipChunkTest bool
skipIterableTest bool
} {
{
name : "no chunk" ,
chks : [ ] [ ] chunks . Sample { } ,
name : "no chunk" ,
sample s: [ ] [ ] chunks . Sample { } ,
} ,
{
name : "one empty chunk" , // This should never happen.
chk s: [ ] [ ] chunks . Sample { { } } ,
name : "one empty chunk" , // This should never happen.
sample s: [ ] [ ] chunks . Sample { { } } ,
expectedChks : [ ] chunks . Meta {
assureChunkFromSamples ( t , [ ] chunks . Sample { } ) ,
} ,
expectedMinMaxTimes : [ ] minMaxTimes { { 0 , 0 } } ,
// iterables with no samples will return no chunks instead of empty chunks
skipIterableTest : true ,
} ,
{
name : "three empty chunks" , // This should never happen.
chks : [ ] [ ] chunks . Sample { { } , { } , { } } ,
name : "one empty iterable" ,
samples : [ ] [ ] chunks . Sample { { } } ,
// iterables with no samples will return no chunks
expectedChks : nil ,
skipChunkTest : true ,
} ,
{
name : "three empty chunks" , // This should never happen.
samples : [ ] [ ] chunks . Sample { { } , { } , { } } ,
expectedChks : [ ] chunks . Meta {
assureChunkFromSamples ( t , [ ] chunks . Sample { } ) ,
@ -756,10 +854,20 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
assureChunkFromSamples ( t , [ ] chunks . Sample { } ) ,
} ,
expectedMinMaxTimes : [ ] minMaxTimes { { 0 , 0 } , { 0 , 0 } , { 0 , 0 } } ,
// iterables with no samples will return no chunks instead of empty chunks
skipIterableTest : true ,
} ,
{
name : "three empty iterables" ,
samples : [ ] [ ] chunks . Sample { { } , { } , { } } ,
// iterables with no samples will return no chunks
expectedChks : nil ,
skipChunkTest : true ,
} ,
{
name : "one chunk" ,
chks : [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
} ,
@ -775,7 +883,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "two full chunks" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -795,7 +903,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "three full chunks" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
{ sample { 10 , 22 , nil , nil } , sample { 203 , 3493 , nil , nil } } ,
@ -819,15 +927,15 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
// Seek cases.
{
name : "three empty chunks and seek" , // This should never happen.
chk s: [ ] [ ] chunks . Sample { { } , { } , { } } ,
seek : 1 ,
name : "three empty chunks and seek" , // This should never happen.
sample s: [ ] [ ] chunks . Sample { { } , { } , { } } ,
seek : 1 ,
seekSuccess : false ,
} ,
{
name : "two chunks and seek beyond chunks" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -837,7 +945,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "two chunks and seek on middle of first chunk" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -850,7 +958,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "two chunks and seek before first chunk" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -864,12 +972,12 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
// Deletion / Trim cases.
{
name : "no chunk with deletion interval" ,
chks : [ ] [ ] chunks . Sample { } ,
samples : [ ] [ ] chunks . Sample { } ,
intervals : tombstones . Intervals { { Mint : 20 , Maxt : 21 } } ,
} ,
{
name : "two chunks with trimmed first and last samples from edge chunks" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -890,7 +998,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "two chunks with trimmed middle sample of first chunk" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -911,7 +1019,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "two chunks with deletion across two chunks" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -933,7 +1041,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
// Deletion with seek.
{
name : "two chunks with trimmed first and last samples from edge chunks, seek from middle of first chunk" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
@ -945,9 +1053,20 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } , sample { 7 , 89 , nil , nil } ,
} ,
} ,
{
name : "one chunk where all samples are trimmed" ,
samples : [ ] [ ] chunks . Sample {
{ sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{ sample { 7 , 89 , nil , nil } , sample { 9 , 8 , nil , nil } } ,
} ,
intervals : tombstones . Intervals { { Mint : math . MinInt64 , Maxt : 3 } } . Add ( tombstones . Interval { Mint : 4 , Maxt : math . MaxInt64 } ) ,
expected : nil ,
expectedChks : nil ,
} ,
{
name : "one histogram chunk" ,
chks : [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , tsdbutil . GenerateTestHistogram ( 1 ) , nil } ,
sample { 2 , 0 , tsdbutil . GenerateTestHistogram ( 2 ) , nil } ,
@ -973,7 +1092,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one histogram chunk intersect with earlier deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , tsdbutil . GenerateTestHistogram ( 1 ) , nil } ,
sample { 2 , 0 , tsdbutil . GenerateTestHistogram ( 2 ) , nil } ,
@ -996,7 +1115,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one histogram chunk intersect with later deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , tsdbutil . GenerateTestHistogram ( 1 ) , nil } ,
sample { 2 , 0 , tsdbutil . GenerateTestHistogram ( 2 ) , nil } ,
@ -1021,7 +1140,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one float histogram chunk" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 1 ) } ,
sample { 2 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 2 ) } ,
@ -1047,7 +1166,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one float histogram chunk intersect with earlier deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 1 ) } ,
sample { 2 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 2 ) } ,
@ -1070,7 +1189,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one float histogram chunk intersect with later deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 1 ) } ,
sample { 2 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 2 ) } ,
@ -1095,7 +1214,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one gauge histogram chunk" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 1 ) , nil } ,
sample { 2 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 2 ) , nil } ,
@ -1121,7 +1240,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one gauge histogram chunk intersect with earlier deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 1 ) , nil } ,
sample { 2 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 2 ) , nil } ,
@ -1144,7 +1263,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one gauge histogram chunk intersect with later deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 1 ) , nil } ,
sample { 2 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 2 ) , nil } ,
@ -1169,7 +1288,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one gauge float histogram" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , nil , tsdbutil . GenerateTestGaugeFloatHistogram ( 1 ) } ,
sample { 2 , 0 , nil , tsdbutil . GenerateTestGaugeFloatHistogram ( 2 ) } ,
@ -1195,7 +1314,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one gauge float histogram chunk intersect with earlier deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , nil , tsdbutil . GenerateTestGaugeFloatHistogram ( 1 ) } ,
sample { 2 , 0 , nil , tsdbutil . GenerateTestGaugeFloatHistogram ( 2 ) } ,
@ -1218,7 +1337,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "one gauge float histogram chunk intersect with later deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 1 , 0 , nil , tsdbutil . GenerateTestGaugeFloatHistogram ( 1 ) } ,
sample { 2 , 0 , nil , tsdbutil . GenerateTestGaugeFloatHistogram ( 2 ) } ,
@ -1243,7 +1362,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "three full mixed chunks" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{ sample { 1 , 2 , nil , nil } , sample { 2 , 3 , nil , nil } , sample { 3 , 5 , nil , nil } , sample { 6 , 1 , nil , nil } } ,
{
sample { 7 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 89 ) , nil } ,
@ -1275,7 +1394,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "three full mixed chunks in different order" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 7 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 89 ) , nil } ,
sample { 9 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 8 ) , nil } ,
@ -1307,7 +1426,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "three full mixed chunks in different order intersect with deletion interval" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 7 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 89 ) , nil } ,
sample { 9 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 8 ) , nil } ,
@ -1338,7 +1457,7 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
{
name : "three full mixed chunks overlapping" ,
chk s: [ ] [ ] chunks . Sample {
sample s: [ ] [ ] chunks . Sample {
{
sample { 7 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 89 ) , nil } ,
sample { 12 , 0 , tsdbutil . GenerateTestGaugeHistogram ( 8 ) , nil } ,
@ -1368,11 +1487,237 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
} ,
expectedMinMaxTimes : [ ] minMaxTimes { { 7 , 12 } , { 11 , 16 } , { 10 , 203 } } ,
} ,
{
// This case won't actually happen until OOO native histograms is implemented.
// Issue: https://github.com/prometheus/prometheus/issues/11220.
name : "int histogram iterables with counter resets" ,
samples : [ ] [ ] chunks . Sample {
{
sample { 7 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 8 , 0 , tsdbutil . GenerateTestHistogram ( 9 ) , nil } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 12 , 0 , tsdbutil . GenerateTestHistogram ( 5 ) , nil } ,
sample { 15 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 16 , 0 , tsdbutil . GenerateTestHistogram ( 7 ) , nil } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 17 , 0 , tsdbutil . GenerateTestHistogram ( 5 ) , nil } ,
} ,
{
sample { 18 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 19 , 0 , tsdbutil . GenerateTestHistogram ( 7 ) , nil } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 20 , 0 , tsdbutil . GenerateTestHistogram ( 5 ) , nil } ,
sample { 21 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
} ,
} ,
expected : [ ] chunks . Sample {
sample { 7 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 8 , 0 , tsdbutil . GenerateTestHistogram ( 9 ) , nil } ,
sample { 12 , 0 , tsdbutil . GenerateTestHistogram ( 5 ) , nil } ,
sample { 15 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 16 , 0 , tsdbutil . GenerateTestHistogram ( 7 ) , nil } ,
sample { 17 , 0 , tsdbutil . GenerateTestHistogram ( 5 ) , nil } ,
sample { 18 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 19 , 0 , tsdbutil . GenerateTestHistogram ( 7 ) , nil } ,
sample { 20 , 0 , tsdbutil . GenerateTestHistogram ( 5 ) , nil } ,
sample { 21 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
} ,
expectedChks : [ ] chunks . Meta {
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 7 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 8 , 0 , tsdbutil . SetHistogramNotCounterReset ( tsdbutil . GenerateTestHistogram ( 9 ) ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 12 , 0 , tsdbutil . SetHistogramCounterReset ( tsdbutil . GenerateTestHistogram ( 5 ) ) , nil } ,
sample { 15 , 0 , tsdbutil . SetHistogramNotCounterReset ( tsdbutil . GenerateTestHistogram ( 6 ) ) , nil } ,
sample { 16 , 0 , tsdbutil . SetHistogramNotCounterReset ( tsdbutil . GenerateTestHistogram ( 7 ) ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 17 , 0 , tsdbutil . SetHistogramCounterReset ( tsdbutil . GenerateTestHistogram ( 5 ) ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 18 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 19 , 0 , tsdbutil . SetHistogramNotCounterReset ( tsdbutil . GenerateTestHistogram ( 7 ) ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 20 , 0 , tsdbutil . SetHistogramCounterReset ( tsdbutil . GenerateTestHistogram ( 5 ) ) , nil } ,
sample { 21 , 0 , tsdbutil . SetHistogramNotCounterReset ( tsdbutil . GenerateTestHistogram ( 6 ) ) , nil } ,
} ) ,
} ,
expectedMinMaxTimes : [ ] minMaxTimes {
{ 7 , 8 } ,
{ 12 , 16 } ,
{ 17 , 17 } ,
{ 18 , 19 } ,
{ 20 , 21 } ,
} ,
// Skipping chunk test - can't create a single chunk for each
// sample slice since there are counter resets in the middle of
// the slices.
skipChunkTest : true ,
} ,
{
// This case won't actually happen until OOO native histograms is implemented.
// Issue: https://github.com/prometheus/prometheus/issues/11220.
name : "float histogram iterables with counter resets" ,
samples : [ ] [ ] chunks . Sample {
{
sample { 7 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 8 ) } ,
sample { 8 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 9 ) } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 12 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 5 ) } ,
sample { 15 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
sample { 16 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 7 ) } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 17 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 5 ) } ,
} ,
{
sample { 18 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
sample { 19 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 7 ) } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 20 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 5 ) } ,
sample { 21 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
} ,
} ,
expected : [ ] chunks . Sample {
sample { 7 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 8 ) } ,
sample { 8 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 9 ) } ,
sample { 12 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 5 ) } ,
sample { 15 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
sample { 16 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 7 ) } ,
sample { 17 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 5 ) } ,
sample { 18 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
sample { 19 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 7 ) } ,
sample { 20 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 5 ) } ,
sample { 21 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
} ,
expectedChks : [ ] chunks . Meta {
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 7 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 8 ) } ,
sample { 8 , 0 , nil , tsdbutil . SetFloatHistogramNotCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 9 ) ) } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 12 , 0 , nil , tsdbutil . SetFloatHistogramCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 5 ) ) } ,
sample { 15 , 0 , nil , tsdbutil . SetFloatHistogramNotCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 6 ) ) } ,
sample { 16 , 0 , nil , tsdbutil . SetFloatHistogramNotCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 7 ) ) } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 17 , 0 , nil , tsdbutil . SetFloatHistogramCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 5 ) ) } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 18 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 6 ) } ,
sample { 19 , 0 , nil , tsdbutil . SetFloatHistogramNotCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 7 ) ) } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 20 , 0 , nil , tsdbutil . SetFloatHistogramCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 5 ) ) } ,
sample { 21 , 0 , nil , tsdbutil . SetFloatHistogramNotCounterReset ( tsdbutil . GenerateTestFloatHistogram ( 6 ) ) } ,
} ) ,
} ,
expectedMinMaxTimes : [ ] minMaxTimes {
{ 7 , 8 } ,
{ 12 , 16 } ,
{ 17 , 17 } ,
{ 18 , 19 } ,
{ 20 , 21 } ,
} ,
// Skipping chunk test - can't create a single chunk for each
// sample slice since there are counter resets in the middle of
// the slices.
skipChunkTest : true ,
} ,
{
// This case won't actually happen until OOO native histograms is implemented.
// Issue: https://github.com/prometheus/prometheus/issues/11220.
name : "iterables with mixed encodings and counter resets" ,
samples : [ ] [ ] chunks . Sample {
{
sample { 7 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 8 , 0 , tsdbutil . GenerateTestHistogram ( 9 ) , nil } ,
sample { 9 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 10 ) } ,
sample { 10 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 11 ) } ,
sample { 11 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 12 ) } ,
sample { 12 , 13 , nil , nil } ,
sample { 13 , 14 , nil , nil } ,
sample { 14 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
// Counter reset should be detected when chunks are created from the iterable.
sample { 15 , 0 , tsdbutil . GenerateTestHistogram ( 7 ) , nil } ,
} ,
{
sample { 18 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 19 , 45 , nil , nil } ,
} ,
} ,
expected : [ ] chunks . Sample {
sample { 7 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 8 , 0 , tsdbutil . GenerateTestHistogram ( 9 ) , nil } ,
sample { 9 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 10 ) } ,
sample { 10 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 11 ) } ,
sample { 11 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 12 ) } ,
sample { 12 , 13 , nil , nil } ,
sample { 13 , 14 , nil , nil } ,
sample { 14 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 15 , 0 , tsdbutil . GenerateTestHistogram ( 7 ) , nil } ,
sample { 18 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
sample { 19 , 45 , nil , nil } ,
} ,
expectedChks : [ ] chunks . Meta {
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 7 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
sample { 8 , 0 , tsdbutil . GenerateTestHistogram ( 9 ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 9 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 10 ) } ,
sample { 10 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 11 ) } ,
sample { 11 , 0 , nil , tsdbutil . GenerateTestFloatHistogram ( 12 ) } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 12 , 13 , nil , nil } ,
sample { 13 , 14 , nil , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 14 , 0 , tsdbutil . GenerateTestHistogram ( 8 ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 15 , 0 , tsdbutil . SetHistogramCounterReset ( tsdbutil . GenerateTestHistogram ( 7 ) ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 18 , 0 , tsdbutil . GenerateTestHistogram ( 6 ) , nil } ,
} ) ,
assureChunkFromSamples ( t , [ ] chunks . Sample {
sample { 19 , 45 , nil , nil } ,
} ) ,
} ,
expectedMinMaxTimes : [ ] minMaxTimes {
{ 7 , 8 } ,
{ 9 , 11 } ,
{ 12 , 13 } ,
{ 14 , 14 } ,
{ 15 , 15 } ,
{ 18 , 18 } ,
{ 19 , 19 } ,
} ,
skipChunkTest : true ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
t . Run ( "sample" , func ( t * testing . T ) {
f , chkMetas := createFakeReaderAndNotPopulatedChunks ( tc . chks ... )
var f * fakeChunksReader
var chkMetas [ ] chunks . Meta
// If the test case wants to skip the chunks test, it probably
// means you can't create valid chunks from sample slices,
// therefore create iterables over the samples instead.
if tc . skipChunkTest {
f , chkMetas = createFakeReaderAndIterables ( tc . samples ... )
} else {
f , chkMetas = createFakeReaderAndNotPopulatedChunks ( tc . samples ... )
}
it := & populateWithDelSeriesIterator { }
it . reset ( ulid . ULID { } , f , chkMetas , tc . intervals )
@ -1393,7 +1738,35 @@ func TestPopulateWithTombSeriesIterators(t *testing.T) {
require . Equal ( t , tc . expected , r )
} )
t . Run ( "chunk" , func ( t * testing . T ) {
f , chkMetas := createFakeReaderAndNotPopulatedChunks ( tc . chks ... )
if tc . skipChunkTest {
t . Skip ( )
}
f , chkMetas := createFakeReaderAndNotPopulatedChunks ( tc . samples ... )
it := & populateWithDelChunkSeriesIterator { }
it . reset ( ulid . ULID { } , f , chkMetas , tc . intervals )
if tc . seek != 0 {
// Chunk iterator does not have Seek method.
return
}
expandedResult , err := storage . ExpandChunks ( it )
require . NoError ( t , err )
// We don't care about ref IDs for comparison, only chunk's samples matters.
rmChunkRefs ( expandedResult )
rmChunkRefs ( tc . expectedChks )
require . Equal ( t , tc . expectedChks , expandedResult )
for i , meta := range expandedResult {
require . Equal ( t , tc . expectedMinMaxTimes [ i ] . minTime , meta . MinTime )
require . Equal ( t , tc . expectedMinMaxTimes [ i ] . maxTime , meta . MaxTime )
}
} )
t . Run ( "iterables" , func ( t * testing . T ) {
if tc . skipIterableTest {
t . Skip ( )
}
f , chkMetas := createFakeReaderAndIterables ( tc . samples ... )
it := & populateWithDelChunkSeriesIterator { }
it . reset ( ulid . ULID { } , f , chkMetas , tc . intervals )
@ -1686,13 +2059,13 @@ func BenchmarkMergedSeriesSet(b *testing.B) {
type mockChunkReader map [ chunks . ChunkRef ] chunkenc . Chunk
func ( cr mockChunkReader ) Chunk ( meta chunks . Meta ) ( chunkenc . Chunk , error ) {
func ( cr mockChunkReader ) ChunkOrIterable ( meta chunks . Meta ) ( chunkenc . Chunk , chunkenc . Iterable , error ) {
chk , ok := cr [ meta . Ref ]
if ok {
return chk , nil
return chk , nil , nil
}
return nil , errors . New ( "Chunk with ref not found" )
return nil , nil , errors . New ( "Chunk with ref not found" )
}
func ( cr mockChunkReader ) Close ( ) error {
@ -3020,7 +3393,7 @@ func TestBlockBaseSeriesSet(t *testing.T) {
idx := tc . expIdxs [ i ]
require . Equal ( t , tc . series [ idx ] . lset , bcs . curr . labels )
require . Equal ( t , tc . series [ idx ] . chunks , si . chk s)
require . Equal ( t , tc . series [ idx ] . chunks , si . meta s)
i ++
}