// findAtOrBefore implements Iterator. func (it *varbitChunkIterator) FindAtOrBefore(t model.Time) bool { if it.len == 0 || t.Before(it.c.FirstTime()) { return false } last := it.c.lastTime() if !t.Before(last) { it.t = last it.v = it.c.lastValue() it.pos = it.len + 1 return true } if t == it.t { return it.lastError == nil } if t.Before(it.t) || it.rewound { it.reset() } var ( prevT = model.Earliest prevV model.SampleValue ) for it.Scan() && t.After(it.t) { prevT = it.t prevV = it.v // TODO(beorn7): If we are in a repeat, we could iterate forward // much faster. } if t == it.t { return it.lastError == nil } it.rewind(prevT, prevV) return it.lastError == nil }
// preloadChunksForInstant preloads chunks for the latest value in the given // range. If the last sample saved in the memorySeries itself is the latest // value in the given range, it will in fact preload zero chunks and just take // that value. func (s *memorySeries) preloadChunksForInstant( fp model.Fingerprint, from model.Time, through model.Time, mss *MemorySeriesStorage, ) (SeriesIterator, error) { // If we have a lastSamplePair in the series, and thas last samplePair // is in the interval, just take it in a singleSampleSeriesIterator. No // need to pin or load anything. lastSample := s.lastSamplePair() if !through.Before(lastSample.Timestamp) && !from.After(lastSample.Timestamp) && lastSample != model.ZeroSamplePair { iter := &boundedIterator{ it: &singleSampleSeriesIterator{ samplePair: lastSample, metric: s.metric, }, start: model.Now().Add(-mss.dropAfter), } return iter, nil } // If we are here, we are out of luck and have to delegate to the more // expensive method. return s.preloadChunksForRange(fp, from, through, mss) }
// ValueAtTime implements SeriesIterator. func (it *memorySeriesIterator) ValueAtTime(t model.Time) []model.SamplePair { // The most common case. We are iterating through a chunk. if it.chunkIt != nil && it.chunkIt.contains(t) { return it.chunkIt.valueAtTime(t) } if len(it.chunks) == 0 { return nil } // Before or exactly on the first sample of the series. it.chunkIt = it.chunkIterator(0) ts := it.chunkIt.timestampAtIndex(0) if !t.After(ts) { // return first value of first chunk return []model.SamplePair{{ Timestamp: ts, Value: it.chunkIt.sampleValueAtIndex(0), }} } // After or exactly on the last sample of the series. it.chunkIt = it.chunkIterator(len(it.chunks) - 1) ts = it.chunkIt.lastTimestamp() if !t.Before(ts) { // return last value of last chunk return []model.SamplePair{{ Timestamp: ts, Value: it.chunkIt.sampleValueAtIndex(it.chunkIt.length() - 1), }} } // Find last chunk where firstTime() is before or equal to t. l := len(it.chunks) - 1 i := sort.Search(len(it.chunks), func(i int) bool { return !it.chunks[l-i].firstTime().After(t) }) if i == len(it.chunks) { panic("out of bounds") } it.chunkIt = it.chunkIterator(l - i) ts = it.chunkIt.lastTimestamp() if t.After(ts) { // We ended up between two chunks. sp1 := model.SamplePair{ Timestamp: ts, Value: it.chunkIt.sampleValueAtIndex(it.chunkIt.length() - 1), } it.chunkIt = it.chunkIterator(l - i + 1) return []model.SamplePair{ sp1, { Timestamp: it.chunkIt.timestampAtIndex(0), Value: it.chunkIt.sampleValueAtIndex(0), }, } } return it.chunkIt.valueAtTime(t) }
// contains implements Iterator. func (it *varbitChunkIterator) Contains(t model.Time) (bool, error) { last, err := it.LastTimestamp() if err != nil { it.lastError = err return false, err } return !t.Before(it.c.FirstTime()) && !t.After(last), it.lastError }
// metricForRange returns the metric for the given fingerprint if the // corresponding time series has samples between 'from' and 'through', together // with a pointer to the series if it is in memory already. For a series that // does not have samples between 'from' and 'through', the returned bool is // false. For an archived series that does contain samples between 'from' and // 'through', it returns (metric, nil, true). // // The caller must have locked the fp. func (s *memorySeriesStorage) metricForRange( fp model.Fingerprint, from, through model.Time, ) (model.Metric, *memorySeries, bool) { series, ok := s.fpToSeries.get(fp) if ok { if series.lastTime.Before(from) || series.firstTime().After(through) { return nil, nil, false } return series.metric, series, true } // From here on, we are only concerned with archived metrics. // If the high watermark of archived series is before 'from', we are done. watermark := model.Time(atomic.LoadInt64((*int64)(&s.archiveHighWatermark))) if watermark < from { return nil, nil, false } if from.After(model.Earliest) || through.Before(model.Latest) { // The range lookup is relatively cheap, so let's do it first if // we have a chance the archived metric is not in the range. has, first, last := s.persistence.hasArchivedMetric(fp) if !has { s.nonExistentSeriesMatchesCount.Inc() return nil, nil, false } if first.After(through) || last.Before(from) { return nil, nil, false } } metric, err := s.persistence.archivedMetric(fp) if err != nil { // archivedMetric has already flagged the storage as dirty in this case. return nil, nil, false } return metric, nil, true }
// findAtOrAfter implements Iterator. func (it *varbitChunkIterator) FindAtOrAfter(t model.Time) bool { if it.len == 0 || t.After(it.c.lastTime()) { return false } first := it.c.FirstTime() if !t.After(first) { it.reset() return it.Scan() } if t == it.t { return it.lastError == nil } if t.Before(it.t) { it.reset() } for it.Scan() && t.After(it.t) { // TODO(beorn7): If we are in a repeat, we could iterate forward // much faster. } return it.lastError == nil }
func (cd *chunkDesc) contains(t model.Time) bool { return !t.Before(cd.firstTime()) && !t.After(cd.lastTime()) }
// contains implements Iterator. func (it *indexAccessingChunkIterator) Contains(t model.Time) (bool, error) { return !t.Before(it.acc.timestampAtIndex(0)) && !t.After(it.acc.timestampAtIndex(it.len-1)), it.acc.err() }
// contains implements chunkIterator. func (it *doubleDeltaEncodedChunkIterator) contains(t model.Time) bool { return !t.Before(it.baseT) && !t.After(it.timestampAtIndex(it.len-1)) }