Return SamplePair istead of *SamplePair consistently

Formalize ZeroSamplePair as return value for non-existing samples.

Change LastSamplePairForFingerprint to return a SamplePair (and not a
pointer to it), which saves allocations in a potentially extremely
frequent call.
This commit is contained in:
beorn7 2016-02-19 16:46:11 +01:00
parent d290340367
commit 1e13f89039
7 changed files with 30 additions and 23 deletions

View file

@ -194,19 +194,19 @@ func (cd *chunkDesc) maybePopulateLastTime() {
}
}
// lastSamplePair returns the last sample pair of the underlying chunk, or nil
// if the chunk is evicted. For safe concurrent access, this method requires the
// fingerprint of the time series to be locked.
// lastSamplePair returns the last sample pair of the underlying chunk, or
// ZeroSampleValue if the chunk is evicted. For safe concurrent access, this
// method requires the fingerprint of the time series to be locked.
// TODO(beorn7): Move up into memorySeries.
func (cd *chunkDesc) lastSamplePair() *model.SamplePair {
func (cd *chunkDesc) lastSamplePair() model.SamplePair {
cd.Lock()
defer cd.Unlock()
if cd.c == nil {
return nil
return ZeroSamplePair
}
it := cd.c.newIterator()
return &model.SamplePair{
return model.SamplePair{
Timestamp: it.lastTimestamp(),
Value: it.lastSampleValue(),
}
@ -293,8 +293,7 @@ type chunkIterator interface {
lastSampleValue() model.SampleValue
// Gets the value that is closest before the given time. In case a value
// exist at precisely the given time, that value is returned. If no
// applicable value exists, a SamplePair with timestamp model.Earliest
// and value 0.0 is returned.
// applicable value exists, ZeroSamplePair is returned.
valueAtOrBeforeTime(model.Time) model.SamplePair
// Gets all values contained within a given interval.
rangeValues(metric.Interval) []model.SamplePair

View file

@ -307,7 +307,7 @@ func (it *deltaEncodedChunkIterator) valueAtOrBeforeTime(t model.Time) model.Sam
return it.timestampAtIndex(i).After(t)
})
if i == 0 {
return model.SamplePair{Timestamp: model.Earliest}
return ZeroSamplePair
}
return model.SamplePair{
Timestamp: it.timestampAtIndex(i - 1),

View file

@ -413,7 +413,7 @@ func (it *doubleDeltaEncodedChunkIterator) valueAtOrBeforeTime(t model.Time) mod
return it.timestampAtIndex(i).After(t)
})
if i == 0 {
return model.SamplePair{Timestamp: model.Earliest}
return ZeroSamplePair
}
return model.SamplePair{
Timestamp: it.timestampAtIndex(i - 1),

View file

@ -42,10 +42,12 @@ type Storage interface {
// label matchers. At least one label matcher must be specified that does not
// match the empty string.
MetricsForLabelMatchers(...*metric.LabelMatcher) map[model.Fingerprint]metric.Metric
// LastSamplePairForFingerprint returns the last sample pair for the
// provided fingerprint. If the respective time series does not exist or
// has an evicted head chunk, nil is returned.
LastSamplePairForFingerprint(model.Fingerprint) *model.SamplePair
// LastSamplePairForFingerprint returns the last sample pair that has
// been ingested for the provided fingerprint. If this instance of the
// Storage has never ingested a sample for the provided fingerprint (or
// the last ingestion is so long ago that the series has been archived),
// ZeroSamplePair is returned.
LastSamplePairForFingerprint(model.Fingerprint) model.SamplePair
// Get all of the label values that are associated with a given label name.
LabelValuesForLabelName(model.LabelName) model.LabelValues
// Get the metric associated with the provided fingerprint.
@ -73,8 +75,7 @@ type Storage interface {
type SeriesIterator interface {
// Gets the value that is closest before the given time. In case a value
// exist at precisely the given time, that value is returned. If no
// applicable value exists, a SamplePair with timestamp model.Earliest
// and value 0.0 is returned.
// applicable value exists, ZeroSamplePair is returned.
ValueAtOrBeforeTime(model.Time) model.SamplePair
// Gets the boundary values of an interval: the first and last value
// within a given interval.
@ -94,3 +95,10 @@ type Preloader interface {
// Close unpins any previously requested series data from memory.
Close()
}
// ZeroSamplePair is the pseudo zero-value of model.SamplePair used by the local
// package to signal a non-existing sample. It is a SamplePair with timestamp
// model.Earliest and value 0.0. Note that the natural zero value of SamplePair
// has a timestamp of 0, which is possible to appear in a real SamplePair and
// thus not suitable to signal a non-existing SamplePair.
var ZeroSamplePair = model.SamplePair{Timestamp: model.Earliest}

View file

@ -479,7 +479,7 @@ func (it *memorySeriesIterator) ValueAtOrBeforeTime(t model.Time) model.SamplePa
}
if len(it.chunks) == 0 {
return model.SamplePair{Timestamp: model.Earliest}
return ZeroSamplePair
}
// Find the last chunk where firstTime() is before or equal to t.
@ -489,7 +489,7 @@ func (it *memorySeriesIterator) ValueAtOrBeforeTime(t model.Time) model.SamplePa
})
if i == len(it.chunks) {
// Even the first chunk starts after t.
return model.SamplePair{Timestamp: model.Earliest}
return ZeroSamplePair
}
it.chunkIt = it.chunkIterator(l - i)
return it.chunkIt.valueAtOrBeforeTime(t)
@ -598,7 +598,7 @@ type nopSeriesIterator struct{}
// ValueAtTime implements SeriesIterator.
func (i nopSeriesIterator) ValueAtOrBeforeTime(t model.Time) model.SamplePair {
return model.SamplePair{Timestamp: model.Earliest}
return ZeroSamplePair
}
// BoundaryValues implements SeriesIterator.

View file

@ -346,13 +346,13 @@ func (s *memorySeriesStorage) WaitForIndexing() {
}
// LastSampleForFingerprint implements Storage.
func (s *memorySeriesStorage) LastSamplePairForFingerprint(fp model.Fingerprint) *model.SamplePair {
func (s *memorySeriesStorage) LastSamplePairForFingerprint(fp model.Fingerprint) model.SamplePair {
s.fpLocker.Lock(fp)
defer s.fpLocker.Unlock(fp)
series, ok := s.fpToSeries.get(fp)
if !ok {
return nil
return ZeroSamplePair
}
return series.head().lastSamplePair()
}
@ -367,7 +367,7 @@ type boundedIterator struct {
// ValueAtOrBeforeTime implements the SeriesIterator interface.
func (bit *boundedIterator) ValueAtOrBeforeTime(ts model.Time) model.SamplePair {
if ts < bit.start {
return model.SamplePair{Timestamp: model.Earliest}
return ZeroSamplePair
}
return bit.it.ValueAtOrBeforeTime(ts)
}

View file

@ -67,7 +67,7 @@ func (h *Handler) federation(w http.ResponseWriter, req *http.Request) {
sp := h.storage.LastSamplePairForFingerprint(fp)
// Discard if sample does not exist or lays before the staleness interval.
if sp == nil || sp.Timestamp.Before(minTimestamp) {
if sp.Timestamp.Before(minTimestamp) {
continue
}