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 // lastSamplePair returns the last sample pair of the underlying chunk, or
// if the chunk is evicted. For safe concurrent access, this method requires the // ZeroSampleValue if the chunk is evicted. For safe concurrent access, this
// fingerprint of the time series to be locked. // method requires the fingerprint of the time series to be locked.
// TODO(beorn7): Move up into memorySeries. // TODO(beorn7): Move up into memorySeries.
func (cd *chunkDesc) lastSamplePair() *model.SamplePair { func (cd *chunkDesc) lastSamplePair() model.SamplePair {
cd.Lock() cd.Lock()
defer cd.Unlock() defer cd.Unlock()
if cd.c == nil { if cd.c == nil {
return nil return ZeroSamplePair
} }
it := cd.c.newIterator() it := cd.c.newIterator()
return &model.SamplePair{ return model.SamplePair{
Timestamp: it.lastTimestamp(), Timestamp: it.lastTimestamp(),
Value: it.lastSampleValue(), Value: it.lastSampleValue(),
} }
@ -293,8 +293,7 @@ type chunkIterator interface {
lastSampleValue() model.SampleValue lastSampleValue() model.SampleValue
// Gets the value that is closest before the given time. In case a value // 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 // exist at precisely the given time, that value is returned. If no
// applicable value exists, a SamplePair with timestamp model.Earliest // applicable value exists, ZeroSamplePair is returned.
// and value 0.0 is returned.
valueAtOrBeforeTime(model.Time) model.SamplePair valueAtOrBeforeTime(model.Time) model.SamplePair
// Gets all values contained within a given interval. // Gets all values contained within a given interval.
rangeValues(metric.Interval) []model.SamplePair 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) return it.timestampAtIndex(i).After(t)
}) })
if i == 0 { if i == 0 {
return model.SamplePair{Timestamp: model.Earliest} return ZeroSamplePair
} }
return model.SamplePair{ return model.SamplePair{
Timestamp: it.timestampAtIndex(i - 1), 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) return it.timestampAtIndex(i).After(t)
}) })
if i == 0 { if i == 0 {
return model.SamplePair{Timestamp: model.Earliest} return ZeroSamplePair
} }
return model.SamplePair{ return model.SamplePair{
Timestamp: it.timestampAtIndex(i - 1), 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 // label matchers. At least one label matcher must be specified that does not
// match the empty string. // match the empty string.
MetricsForLabelMatchers(...*metric.LabelMatcher) map[model.Fingerprint]metric.Metric MetricsForLabelMatchers(...*metric.LabelMatcher) map[model.Fingerprint]metric.Metric
// LastSamplePairForFingerprint returns the last sample pair for the // LastSamplePairForFingerprint returns the last sample pair that has
// provided fingerprint. If the respective time series does not exist or // been ingested for the provided fingerprint. If this instance of the
// has an evicted head chunk, nil is returned. // Storage has never ingested a sample for the provided fingerprint (or
LastSamplePairForFingerprint(model.Fingerprint) *model.SamplePair // 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. // Get all of the label values that are associated with a given label name.
LabelValuesForLabelName(model.LabelName) model.LabelValues LabelValuesForLabelName(model.LabelName) model.LabelValues
// Get the metric associated with the provided fingerprint. // Get the metric associated with the provided fingerprint.
@ -73,8 +75,7 @@ type Storage interface {
type SeriesIterator interface { type SeriesIterator interface {
// Gets the value that is closest before the given time. In case a value // 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 // exist at precisely the given time, that value is returned. If no
// applicable value exists, a SamplePair with timestamp model.Earliest // applicable value exists, ZeroSamplePair is returned.
// and value 0.0 is returned.
ValueAtOrBeforeTime(model.Time) model.SamplePair ValueAtOrBeforeTime(model.Time) model.SamplePair
// Gets the boundary values of an interval: the first and last value // Gets the boundary values of an interval: the first and last value
// within a given interval. // within a given interval.
@ -94,3 +95,10 @@ type Preloader interface {
// Close unpins any previously requested series data from memory. // Close unpins any previously requested series data from memory.
Close() 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 { 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. // 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) { if i == len(it.chunks) {
// Even the first chunk starts after t. // Even the first chunk starts after t.
return model.SamplePair{Timestamp: model.Earliest} return ZeroSamplePair
} }
it.chunkIt = it.chunkIterator(l - i) it.chunkIt = it.chunkIterator(l - i)
return it.chunkIt.valueAtOrBeforeTime(t) return it.chunkIt.valueAtOrBeforeTime(t)
@ -598,7 +598,7 @@ type nopSeriesIterator struct{}
// ValueAtTime implements SeriesIterator. // ValueAtTime implements SeriesIterator.
func (i nopSeriesIterator) ValueAtOrBeforeTime(t model.Time) model.SamplePair { func (i nopSeriesIterator) ValueAtOrBeforeTime(t model.Time) model.SamplePair {
return model.SamplePair{Timestamp: model.Earliest} return ZeroSamplePair
} }
// BoundaryValues implements SeriesIterator. // BoundaryValues implements SeriesIterator.

View file

@ -346,13 +346,13 @@ func (s *memorySeriesStorage) WaitForIndexing() {
} }
// LastSampleForFingerprint implements Storage. // 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) s.fpLocker.Lock(fp)
defer s.fpLocker.Unlock(fp) defer s.fpLocker.Unlock(fp)
series, ok := s.fpToSeries.get(fp) series, ok := s.fpToSeries.get(fp)
if !ok { if !ok {
return nil return ZeroSamplePair
} }
return series.head().lastSamplePair() return series.head().lastSamplePair()
} }
@ -367,7 +367,7 @@ type boundedIterator struct {
// ValueAtOrBeforeTime implements the SeriesIterator interface. // ValueAtOrBeforeTime implements the SeriesIterator interface.
func (bit *boundedIterator) ValueAtOrBeforeTime(ts model.Time) model.SamplePair { func (bit *boundedIterator) ValueAtOrBeforeTime(ts model.Time) model.SamplePair {
if ts < bit.start { if ts < bit.start {
return model.SamplePair{Timestamp: model.Earliest} return ZeroSamplePair
} }
return bit.it.ValueAtOrBeforeTime(ts) 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) sp := h.storage.LastSamplePairForFingerprint(fp)
// Discard if sample does not exist or lays before the staleness interval. // 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 continue
} }