| 
									
										
										
										
											2017-04-19 20:43:09 +08:00
										 |  |  | // Copyright 2017 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | package storage | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"math/rand" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestSampleRing(t *testing.T) { | 
					
						
							|  |  |  | 	cases := []struct { | 
					
						
							|  |  |  | 		input []int64 | 
					
						
							|  |  |  | 		delta int64 | 
					
						
							|  |  |  | 		size  int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			input: []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, | 
					
						
							|  |  |  | 			delta: 2, | 
					
						
							|  |  |  | 			size:  1, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			input: []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, | 
					
						
							|  |  |  | 			delta: 2, | 
					
						
							|  |  |  | 			size:  2, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			input: []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, | 
					
						
							|  |  |  | 			delta: 7, | 
					
						
							|  |  |  | 			size:  3, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			input: []int64{1, 2, 3, 4, 5, 16, 17, 18, 19, 20}, | 
					
						
							|  |  |  | 			delta: 7, | 
					
						
							|  |  |  | 			size:  1, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2018-03-12 21:16:59 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			input: []int64{1, 2, 3, 4, 6}, | 
					
						
							|  |  |  | 			delta: 4, | 
					
						
							|  |  |  | 			size:  4, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, c := range cases { | 
					
						
							|  |  |  | 		r := newSampleRing(c.delta, c.size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		input := []sample{} | 
					
						
							|  |  |  | 		for _, t := range c.input { | 
					
						
							|  |  |  | 			input = append(input, sample{ | 
					
						
							|  |  |  | 				t: t, | 
					
						
							|  |  |  | 				v: float64(rand.Intn(100)), | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for i, s := range input { | 
					
						
							|  |  |  | 			r.add(s.t, s.v) | 
					
						
							|  |  |  | 			buffered := r.samples() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for _, sold := range input[:i] { | 
					
						
							|  |  |  | 				found := false | 
					
						
							|  |  |  | 				for _, bs := range buffered { | 
					
						
							|  |  |  | 					if bs.t == sold.t && bs.v == sold.v { | 
					
						
							|  |  |  | 						found = true | 
					
						
							|  |  |  | 						break | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-10-02 13:28:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if found { | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 					require.GreaterOrEqual(t, sold.t, s.t-c.delta, "%d: unexpected sample %d in buffer; buffer %v", i, sold.t, buffered) | 
					
						
							| 
									
										
										
										
											2019-10-02 13:28:08 +08:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 					require.Less(t, sold.t, s.t-c.delta, "%d: expected sample %d to be in buffer but was not; buffer %v", i, sold.t, buffered) | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestBufferedSeriesIterator(t *testing.T) { | 
					
						
							|  |  |  | 	var it *BufferedSeriesIterator | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bufferEq := func(exp []sample) { | 
					
						
							|  |  |  | 		var b []sample | 
					
						
							|  |  |  | 		bit := it.Buffer() | 
					
						
							|  |  |  | 		for bit.Next() { | 
					
						
							| 
									
										
										
										
											2017-01-02 20:33:37 +08:00
										 |  |  | 			t, v := bit.At() | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 			b = append(b, sample{t: t, v: v}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 		require.Equal(t, exp, b, "buffer mismatch") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	sampleEq := func(ets int64, ev float64) { | 
					
						
							| 
									
										
										
										
											2021-11-29 18:16:40 +08:00
										 |  |  | 		ts, v := it.At() | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 		require.Equal(t, ets, ts, "timestamp mismatch") | 
					
						
							|  |  |  | 		require.Equal(t, ev, v, "value mismatch") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-11 21:32:56 +08:00
										 |  |  | 	prevSampleEq := func(ets int64, ev float64, eok bool) { | 
					
						
							|  |  |  | 		ts, v, ok := it.PeekBack(1) | 
					
						
							|  |  |  | 		require.Equal(t, eok, ok, "exist mismatch") | 
					
						
							|  |  |  | 		require.Equal(t, ets, ts, "timestamp mismatch") | 
					
						
							|  |  |  | 		require.Equal(t, ev, v, "value mismatch") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 21:41:52 +08:00
										 |  |  | 	it = NewBufferIterator(NewListSeriesIterator(samples{ | 
					
						
							| 
									
										
										
										
											2020-03-25 04:15:47 +08:00
										 |  |  | 		sample{t: 1, v: 2}, | 
					
						
							|  |  |  | 		sample{t: 2, v: 3}, | 
					
						
							|  |  |  | 		sample{t: 3, v: 4}, | 
					
						
							|  |  |  | 		sample{t: 4, v: 5}, | 
					
						
							|  |  |  | 		sample{t: 5, v: 6}, | 
					
						
							|  |  |  | 		sample{t: 99, v: 8}, | 
					
						
							|  |  |  | 		sample{t: 100, v: 9}, | 
					
						
							|  |  |  | 		sample{t: 101, v: 10}, | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	}), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.True(t, it.Seek(-123), "seek failed") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	sampleEq(1, 2) | 
					
						
							| 
									
										
										
										
											2021-03-11 21:32:56 +08:00
										 |  |  | 	prevSampleEq(0, 0, false) | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	bufferEq(nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.True(t, it.Next(), "next failed") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	sampleEq(2, 3) | 
					
						
							| 
									
										
										
										
											2021-03-11 21:32:56 +08:00
										 |  |  | 	prevSampleEq(1, 2, true) | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	bufferEq([]sample{{t: 1, v: 2}}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.True(t, it.Next(), "next failed") | 
					
						
							|  |  |  | 	require.True(t, it.Next(), "next failed") | 
					
						
							|  |  |  | 	require.True(t, it.Next(), "next failed") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	sampleEq(5, 6) | 
					
						
							| 
									
										
										
										
											2021-03-11 21:32:56 +08:00
										 |  |  | 	prevSampleEq(4, 5, true) | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	bufferEq([]sample{{t: 2, v: 3}, {t: 3, v: 4}, {t: 4, v: 5}}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.True(t, it.Seek(5), "seek failed") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	sampleEq(5, 6) | 
					
						
							| 
									
										
										
										
											2021-03-11 21:32:56 +08:00
										 |  |  | 	prevSampleEq(4, 5, true) | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	bufferEq([]sample{{t: 2, v: 3}, {t: 3, v: 4}, {t: 4, v: 5}}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.True(t, it.Seek(101), "seek failed") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	sampleEq(101, 10) | 
					
						
							| 
									
										
										
										
											2021-03-11 21:32:56 +08:00
										 |  |  | 	prevSampleEq(100, 9, true) | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | 	bufferEq([]sample{{t: 99, v: 8}, {t: 100, v: 9}}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.False(t, it.Next(), "next succeeded unexpectedly") | 
					
						
							| 
									
										
										
										
											2016-12-25 08:40:28 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-12-30 17:45:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-13 13:22:27 +08:00
										 |  |  | // At() should not be called once Next() returns false.
 | 
					
						
							|  |  |  | func TestBufferedSeriesIteratorNoBadAt(t *testing.T) { | 
					
						
							|  |  |  | 	done := false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m := &mockSeriesIterator{ | 
					
						
							|  |  |  | 		seek: func(int64) bool { return false }, | 
					
						
							|  |  |  | 		at: func() (int64, float64) { | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.False(t, done, "unexpectedly done") | 
					
						
							| 
									
										
										
										
											2017-06-13 13:22:27 +08:00
										 |  |  | 			done = true | 
					
						
							|  |  |  | 			return 0, 0 | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		next: func() bool { return !done }, | 
					
						
							|  |  |  | 		err:  func() error { return nil }, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 12:10:28 +08:00
										 |  |  | 	it := NewBufferIterator(m, 60) | 
					
						
							| 
									
										
										
										
											2017-06-13 13:22:27 +08:00
										 |  |  | 	it.Next() | 
					
						
							|  |  |  | 	it.Next() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 17:57:34 +08:00
										 |  |  | func BenchmarkBufferedSeriesIterator(b *testing.B) { | 
					
						
							|  |  |  | 	// Simulate a 5 minute rate.
 | 
					
						
							| 
									
										
										
										
											2018-12-18 19:22:33 +08:00
										 |  |  | 	it := NewBufferIterator(newFakeSeriesIterator(int64(b.N), 30), 5*60) | 
					
						
							| 
									
										
										
										
											2017-03-14 17:57:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	b.SetBytes(int64(b.N * 16)) | 
					
						
							|  |  |  | 	b.ReportAllocs() | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		// scan everything
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(b, it.Err()) | 
					
						
							| 
									
										
										
										
											2017-03-14 17:57:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 17:45:56 +08:00
										 |  |  | type mockSeriesIterator struct { | 
					
						
							| 
									
										
										
										
											2017-06-13 13:22:27 +08:00
										 |  |  | 	seek func(int64) bool | 
					
						
							|  |  |  | 	at   func() (int64, float64) | 
					
						
							|  |  |  | 	next func() bool | 
					
						
							|  |  |  | 	err  func() error | 
					
						
							| 
									
										
										
										
											2016-12-30 17:45:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-13 13:22:27 +08:00
										 |  |  | func (m *mockSeriesIterator) Seek(t int64) bool    { return m.seek(t) } | 
					
						
							|  |  |  | func (m *mockSeriesIterator) At() (int64, float64) { return m.at() } | 
					
						
							|  |  |  | func (m *mockSeriesIterator) Next() bool           { return m.next() } | 
					
						
							|  |  |  | func (m *mockSeriesIterator) Err() error           { return m.err() } | 
					
						
							| 
									
										
										
										
											2016-12-30 17:45:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 19:22:33 +08:00
										 |  |  | type fakeSeriesIterator struct { | 
					
						
							|  |  |  | 	nsamples int64 | 
					
						
							|  |  |  | 	step     int64 | 
					
						
							|  |  |  | 	idx      int64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newFakeSeriesIterator(nsamples, step int64) *fakeSeriesIterator { | 
					
						
							|  |  |  | 	return &fakeSeriesIterator{nsamples: nsamples, step: step, idx: -1} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (it *fakeSeriesIterator) At() (int64, float64) { | 
					
						
							|  |  |  | 	return it.idx * it.step, 123 // value doesn't matter
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (it *fakeSeriesIterator) Next() bool { | 
					
						
							|  |  |  | 	it.idx++ | 
					
						
							|  |  |  | 	return it.idx < it.nsamples | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (it *fakeSeriesIterator) Seek(t int64) bool { | 
					
						
							|  |  |  | 	it.idx = t / it.step | 
					
						
							|  |  |  | 	return it.idx < it.nsamples | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-25 04:15:47 +08:00
										 |  |  | func (it *fakeSeriesIterator) Err() error { return nil } |