|
|
|
@ -400,6 +400,203 @@ type MetricIndexer interface {
|
|
|
|
|
IndexMetrics(FingerprintMetricMapping) error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IndexObserver listens and receives changes to a given
|
|
|
|
|
// FingerprintMetricMapping.
|
|
|
|
|
type IndexerObserver interface { |
|
|
|
|
Observe(FingerprintMetricMapping) error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IndexerProxy receives IndexMetric requests and proxies them to the underlying
|
|
|
|
|
// MetricIndexer. Upon success of the underlying receiver, the registered
|
|
|
|
|
// IndexObservers are called serially.
|
|
|
|
|
//
|
|
|
|
|
// If an error occurs in the underlying MetricIndexer or any of the observers,
|
|
|
|
|
// this proxy will not work any further and return the offending error in this
|
|
|
|
|
// call or any subsequent ones.
|
|
|
|
|
type IndexerProxy struct { |
|
|
|
|
err error |
|
|
|
|
|
|
|
|
|
i MetricIndexer |
|
|
|
|
observers []IndexerObserver |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (p *IndexerProxy) IndexMetrics(b FingerprintMetricMapping) error { |
|
|
|
|
if p.err != nil { |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
if p.err = p.i.IndexMetrics(b); p.err != nil { |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, o := range p.observers { |
|
|
|
|
if p.err = o.Observe(b); p.err != nil { |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Close closes the underlying indexer.
|
|
|
|
|
func (p *IndexerProxy) Close() error { |
|
|
|
|
if p.err != nil { |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
if closer, ok := p.i.(io.Closer); ok { |
|
|
|
|
p.err = closer.Close() |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Close flushes the underlying index requests before closing.
|
|
|
|
|
func (p *IndexerProxy) Flush() error { |
|
|
|
|
if p.err != nil { |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
if flusher, ok := p.i.(flusher); ok { |
|
|
|
|
p.err = flusher.Flush() |
|
|
|
|
return p.err |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewIndexerProxy builds an IndexerProxy for the given configuration.
|
|
|
|
|
func NewIndexerProxy(i MetricIndexer, o ...IndexerObserver) *IndexerProxy { |
|
|
|
|
return &IndexerProxy{ |
|
|
|
|
i: i, |
|
|
|
|
observers: o, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// SynchronizedIndexer provides naive locking for any MetricIndexer.
|
|
|
|
|
type SynchronizedIndexer struct { |
|
|
|
|
mu sync.Mutex |
|
|
|
|
i MetricIndexer |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (i *SynchronizedIndexer) IndexMetrics(b FingerprintMetricMapping) error { |
|
|
|
|
i.mu.Lock() |
|
|
|
|
defer i.mu.Unlock() |
|
|
|
|
|
|
|
|
|
return i.i.IndexMetrics(b) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type flusher interface { |
|
|
|
|
Flush() error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (i *SynchronizedIndexer) Flush() error { |
|
|
|
|
if flusher, ok := i.i.(flusher); ok { |
|
|
|
|
i.mu.Lock() |
|
|
|
|
defer i.mu.Unlock() |
|
|
|
|
|
|
|
|
|
return flusher.Flush() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (i *SynchronizedIndexer) Close() error { |
|
|
|
|
if closer, ok := i.i.(io.Closer); ok { |
|
|
|
|
i.mu.Lock() |
|
|
|
|
defer i.mu.Unlock() |
|
|
|
|
|
|
|
|
|
return closer.Close() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewSynchronizedIndexer builds a new MetricIndexer.
|
|
|
|
|
func NewSynchronizedIndexer(i MetricIndexer) *SynchronizedIndexer { |
|
|
|
|
return &SynchronizedIndexer{ |
|
|
|
|
i: i, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// BufferedIndexer provides unsynchronized index buffering.
|
|
|
|
|
//
|
|
|
|
|
// If an error occurs in the underlying MetricIndexer or any of the observers,
|
|
|
|
|
// this proxy will not work any further and return the offending error.
|
|
|
|
|
type BufferedIndexer struct { |
|
|
|
|
i MetricIndexer |
|
|
|
|
|
|
|
|
|
limit int |
|
|
|
|
|
|
|
|
|
buf []FingerprintMetricMapping |
|
|
|
|
|
|
|
|
|
err error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (i *BufferedIndexer) IndexMetrics(b FingerprintMetricMapping) error { |
|
|
|
|
if i.err != nil { |
|
|
|
|
return i.err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(i.buf) < i.limit { |
|
|
|
|
i.buf = append(i.buf, b) |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
i.buf = append(i.buf) |
|
|
|
|
|
|
|
|
|
i.err = i.Flush() |
|
|
|
|
|
|
|
|
|
return i.err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Flush writes all pending entries to the index.
|
|
|
|
|
func (i *BufferedIndexer) Flush() error { |
|
|
|
|
if i.err != nil { |
|
|
|
|
return i.err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(i.buf) == 0 { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
superset := FingerprintMetricMapping{} |
|
|
|
|
for _, b := range i.buf { |
|
|
|
|
for fp, m := range b { |
|
|
|
|
if _, ok := superset[fp]; ok { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
superset[fp] = m |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
i.buf = make([]FingerprintMetricMapping, 0, i.limit) |
|
|
|
|
|
|
|
|
|
i.err = i.i.IndexMetrics(superset) |
|
|
|
|
|
|
|
|
|
return i.err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Close flushes and closes the underlying buffer.
|
|
|
|
|
func (i *BufferedIndexer) Close() error { |
|
|
|
|
if err := i.Flush(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if closer, ok := i.i.(io.Closer); ok { |
|
|
|
|
return closer.Close() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func NewBufferedIndexer(i MetricIndexer, limit int) *BufferedIndexer { |
|
|
|
|
|
|
|
|
|
return &BufferedIndexer{ |
|
|
|
|
i: i, |
|
|
|
|
limit: limit, |
|
|
|
|
buf: make([]FingerprintMetricMapping, 0, limit), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TotalIndexer is a MetricIndexer that indexes all standard facets of a metric
|
|
|
|
|
// that a user or the Prometheus subsystem would want to query against:
|
|
|
|
|
//
|
|
|
|
|