mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Merge pull request #738 from prometheus/fabxc/retention-cutoff
Limit retrievable samples to retention window.
This commit is contained in:
commit
078efa6e6a
|
@ -44,6 +44,8 @@ type Storage interface {
|
||||||
// Get the metric associated with the provided fingerprint.
|
// Get the metric associated with the provided fingerprint.
|
||||||
MetricForFingerprint(clientmodel.Fingerprint) clientmodel.COWMetric
|
MetricForFingerprint(clientmodel.Fingerprint) clientmodel.COWMetric
|
||||||
// Construct an iterator for a given fingerprint.
|
// Construct an iterator for a given fingerprint.
|
||||||
|
// The iterator will never return samples older than retention time,
|
||||||
|
// relative to the time NewIterator was called.
|
||||||
NewIterator(clientmodel.Fingerprint) SeriesIterator
|
NewIterator(clientmodel.Fingerprint) SeriesIterator
|
||||||
// Run the various maintenance loops in goroutines. Returns when the
|
// Run the various maintenance loops in goroutines. Returns when the
|
||||||
// storage is ready to use. Keeps everything running in the background
|
// storage is ready to use. Keeps everything running in the background
|
||||||
|
|
|
@ -286,7 +286,47 @@ func (s *memorySeriesStorage) NewIterator(fp clientmodel.Fingerprint) SeriesIter
|
||||||
// return any values.
|
// return any values.
|
||||||
return nopSeriesIterator{}
|
return nopSeriesIterator{}
|
||||||
}
|
}
|
||||||
return series.newIterator()
|
return &boundedIterator{
|
||||||
|
it: series.newIterator(),
|
||||||
|
start: clientmodel.Now().Add(-s.dropAfter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// boundedIterator wraps a SeriesIterator and does not allow fetching
|
||||||
|
// data from earlier than the configured start time.
|
||||||
|
type boundedIterator struct {
|
||||||
|
it SeriesIterator
|
||||||
|
start clientmodel.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueAtTime implements the SeriesIterator interface.
|
||||||
|
func (bit *boundedIterator) ValueAtTime(ts clientmodel.Timestamp) metric.Values {
|
||||||
|
if ts < bit.start {
|
||||||
|
return metric.Values{}
|
||||||
|
}
|
||||||
|
return bit.it.ValueAtTime(ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoundaryValues implements the SeriesIterator interface.
|
||||||
|
func (bit *boundedIterator) BoundaryValues(interval metric.Interval) metric.Values {
|
||||||
|
if interval.NewestInclusive < bit.start {
|
||||||
|
return metric.Values{}
|
||||||
|
}
|
||||||
|
if interval.OldestInclusive < bit.start {
|
||||||
|
interval.OldestInclusive = bit.start
|
||||||
|
}
|
||||||
|
return bit.it.BoundaryValues(interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeValues implements the SeriesIterator interface.
|
||||||
|
func (bit *boundedIterator) RangeValues(interval metric.Interval) metric.Values {
|
||||||
|
if interval.NewestInclusive < bit.start {
|
||||||
|
return metric.Values{}
|
||||||
|
}
|
||||||
|
if interval.OldestInclusive < bit.start {
|
||||||
|
interval.OldestInclusive = bit.start
|
||||||
|
}
|
||||||
|
return bit.it.RangeValues(interval)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPreloader implements Storage.
|
// NewPreloader implements Storage.
|
||||||
|
|
|
@ -140,6 +140,70 @@ func TestFingerprintsForLabelMatchers(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRetentionCutoff(t *testing.T) {
|
||||||
|
now := clientmodel.Now()
|
||||||
|
insertStart := now.Add(-2 * time.Hour)
|
||||||
|
|
||||||
|
s, closer := NewTestStorage(t, 1)
|
||||||
|
defer closer.Close()
|
||||||
|
|
||||||
|
// Stop maintenance loop to prevent actual purging.
|
||||||
|
s.loopStopping <- struct{}{}
|
||||||
|
|
||||||
|
s.dropAfter = 1 * time.Hour
|
||||||
|
|
||||||
|
samples := make(clientmodel.Samples, 120)
|
||||||
|
for i := range samples {
|
||||||
|
smpl := &clientmodel.Sample{
|
||||||
|
Metric: clientmodel.Metric{"job": "test"},
|
||||||
|
Timestamp: insertStart.Add(time.Duration(i) * time.Minute), // 1 minute intervals.
|
||||||
|
Value: 1,
|
||||||
|
}
|
||||||
|
s.Append(smpl)
|
||||||
|
}
|
||||||
|
s.WaitForIndexing()
|
||||||
|
|
||||||
|
lm, err := metric.NewLabelMatcher(metric.Equal, "job", "test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error creating label matcher: %s", err)
|
||||||
|
}
|
||||||
|
fp := s.FingerprintsForLabelMatchers(metric.LabelMatchers{lm})[0]
|
||||||
|
|
||||||
|
pl := s.NewPreloader()
|
||||||
|
defer pl.Close()
|
||||||
|
|
||||||
|
// Preload everything.
|
||||||
|
err = pl.PreloadRange(fp, insertStart, now, 5*time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error preloading outdated chunks: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
it := s.NewIterator(fp)
|
||||||
|
|
||||||
|
vals := it.ValueAtTime(now.Add(-61 * time.Minute))
|
||||||
|
if len(vals) != 0 {
|
||||||
|
t.Errorf("unexpected result for timestamp before retention period")
|
||||||
|
}
|
||||||
|
|
||||||
|
vals = it.RangeValues(metric.Interval{insertStart, now})
|
||||||
|
// We get 59 values here because the clientmodel.Now() is slightly later
|
||||||
|
// than our now.
|
||||||
|
if len(vals) != 59 {
|
||||||
|
t.Errorf("expected 59 values but got %d", len(vals))
|
||||||
|
}
|
||||||
|
if expt := now.Add(-1 * time.Hour).Add(time.Minute); vals[0].Timestamp != expt {
|
||||||
|
t.Errorf("unexpected timestamp for first sample: %v, expected %v", vals[0].Timestamp.Time(), expt.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
vals = it.BoundaryValues(metric.Interval{insertStart, now})
|
||||||
|
if len(vals) != 2 {
|
||||||
|
t.Errorf("expected 2 values but got %d", len(vals))
|
||||||
|
}
|
||||||
|
if expt := now.Add(-1 * time.Hour).Add(time.Minute); vals[0].Timestamp != expt {
|
||||||
|
t.Errorf("unexpected timestamp for first sample: %v, expected %v", vals[0].Timestamp.Time(), expt.Time())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestLoop is just a smoke test for the loop method, if we can switch it on and
|
// TestLoop is just a smoke test for the loop method, if we can switch it on and
|
||||||
// off without disaster.
|
// off without disaster.
|
||||||
func TestLoop(t *testing.T) {
|
func TestLoop(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue