package index import ( "sync" clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/prometheus/storage/metric" "github.com/prometheus/prometheus/utility" ) // FingerprintMetricMapping is an in-memory map of fingerprints to metrics. type FingerprintMetricMapping map[clientmodel.Fingerprint]clientmodel.Metric // FingerprintMetricIndex models a database mapping fingerprints to metrics. type FingerprintMetricIndex struct { KeyValueStore } // IndexBatch indexes a batch of mappings from fingerprints to metrics. func (i *FingerprintMetricIndex) IndexBatch(mapping FingerprintMetricMapping) error { b := i.NewBatch() for fp, m := range mapping { b.Put(codableFingerprint(fp), codableMetric(m)) } return i.Commit(b) } // UnindexBatch unindexes a batch of mappings from fingerprints to metrics. func (i *FingerprintMetricIndex) UnindexBatch(mapping FingerprintMetricMapping) error { b := i.NewBatch() for fp, _ := range mapping { b.Delete(codableFingerprint(fp)) } return i.Commit(b) } // Lookup looks up a metric by fingerprint. func (i *FingerprintMetricIndex) Lookup(fp clientmodel.Fingerprint) (m clientmodel.Metric, ok bool, err error) { m = clientmodel.Metric{} if ok, err := i.Get(codableFingerprint(fp), codableMetric(m)); !ok { return nil, false, nil } else if err != nil { return nil, false, err } return m, true, nil } // NewFingerprintMetricIndex returns a FingerprintMetricIndex // object ready to use. func NewFingerprintMetricIndex(db KeyValueStore) *FingerprintMetricIndex { return &FingerprintMetricIndex{ KeyValueStore: db, } } // LabelNameLabelValuesMapping is an in-memory map of label names to // label values. type LabelNameLabelValuesMapping map[clientmodel.LabelName]clientmodel.LabelValues // LabelNameLabelValuesIndex models a database mapping label names to // label values. type LabelNameLabelValuesIndex struct { KeyValueStore } // IndexBatch implements LabelNameLabelValuesIndex. func (i *LabelNameLabelValuesIndex) IndexBatch(b LabelNameLabelValuesMapping) error { batch := i.NewBatch() for name, values := range b { if len(values) == 0 { batch.Delete(codableLabelName(name)) } else { batch.Put(codableLabelName(name), codableLabelValues(values)) } } return i.Commit(batch) } // Lookup looks up all label values for a given label name. func (i *LabelNameLabelValuesIndex) Lookup(l clientmodel.LabelName) (values clientmodel.LabelValues, ok bool, err error) { ok, err = i.Get(codableLabelName(l), (*codableLabelValues)(&values)) if err != nil { return nil, false, err } if !ok { return nil, false, nil } return values, true, nil } // NewLabelNameLabelValuesIndex returns a LabelNameLabelValuesIndex // ready to use. func NewLabelNameLabelValuesIndex(db KeyValueStore) *LabelNameLabelValuesIndex { return &LabelNameLabelValuesIndex{ KeyValueStore: db, } } // LabelPairFingerprintsMapping is an in-memory map of label pairs to // fingerprints. type LabelPairFingerprintsMapping map[metric.LabelPair]clientmodel.Fingerprints // LabelPairFingerprintIndex models a database mapping label pairs to // fingerprints. type LabelPairFingerprintIndex struct { KeyValueStore } // IndexBatch indexes a batch of mappings from label pairs to fingerprints. func (i *LabelPairFingerprintIndex) IndexBatch(m LabelPairFingerprintsMapping) error { batch := i.NewBatch() for pair, fps := range m { if len(fps) == 0 { batch.Delete(codableLabelPair(pair)) } else { batch.Put(codableLabelPair(pair), codableFingerprints(fps)) } } return i.Commit(batch) } // Lookup looks up all fingerprints for a given label pair. func (i *LabelPairFingerprintIndex) Lookup(p *metric.LabelPair) (fps clientmodel.Fingerprints, ok bool, err error) { ok, err = i.Get((*codableLabelPair)(p), (*codableFingerprints)(&fps)) if !ok { return nil, false, nil } if err != nil { return nil, false, err } return fps, true, nil } // NewLabelPairFingerprintIndex returns a LabelPairFingerprintIndex // object ready to use. func NewLabelPairFingerprintIndex(db KeyValueStore) *LabelPairFingerprintIndex { return &LabelPairFingerprintIndex{ KeyValueStore: db, } } // FingerprintMembershipIndex models a database tracking the existence // of metrics by their fingerprints. type FingerprintMembershipIndex struct { KeyValueStore } // IndexBatch indexes a batch of fingerprints. func (i *FingerprintMembershipIndex) IndexBatch(b FingerprintMetricMapping) error { batch := i.NewBatch() for fp, _ := range b { batch.Put(codableFingerprint(fp), codableMembership{}) } return i.Commit(batch) } // UnindexBatch unindexes a batch of fingerprints. func (i *FingerprintMembershipIndex) UnindexBatch(b FingerprintMetricMapping) error { batch := i.NewBatch() for fp, _ := range b { batch.Delete(codableFingerprint(fp)) } return i.Commit(batch) } // Has returns true if the given fingerprint is present. func (i *FingerprintMembershipIndex) Has(fp clientmodel.Fingerprint) (ok bool, err error) { return i.KeyValueStore.Has(codableFingerprint(fp)) } // NewFingerprintMembershipIndex returns a FingerprintMembershipIndex object // ready to use. func NewFingerprintMembershipIndex(db KeyValueStore) *FingerprintMembershipIndex { return &FingerprintMembershipIndex{ KeyValueStore: db, } } // TODO(julius): Currently unused, is it needed? // SynchronizedIndexer provides naive locking for any MetricIndexer. type SynchronizedIndexer struct { mu sync.Mutex i MetricIndexer } // IndexMetrics calls IndexMetrics of the wrapped MetricIndexer after acquiring // a lock. func (i *SynchronizedIndexer) IndexMetrics(b FingerprintMetricMapping) error { i.mu.Lock() defer i.mu.Unlock() return i.i.IndexMetrics(b) } // TotalIndexer is a MetricIndexer that indexes all standard facets of a metric // that a user or the Prometheus subsystem would want to query against: // // -> //