2014-08-21 20:06:11 +00:00
package index
import (
2014-09-09 13:13:07 +00:00
"flag"
"path"
2014-08-21 20:06:11 +00:00
clientmodel "github.com/prometheus/client_golang/model"
2014-09-10 16:41:52 +00:00
"github.com/prometheus/prometheus/storage/local/codec"
2014-08-21 20:06:11 +00:00
"github.com/prometheus/prometheus/storage/metric"
"github.com/prometheus/prometheus/utility"
)
2014-09-09 13:13:07 +00:00
const (
2014-09-10 16:41:52 +00:00
fingerprintToMetricDir = "archived_fingerprint_to_metric"
fingerprintTimeRangeDir = "archived_fingerprint_to_timerange"
2014-09-09 13:13:07 +00:00
labelNameToLabelValuesDir = "labelname_to_labelvalues"
labelPairToFingerprintsDir = "labelpair_to_fingerprints"
)
var (
fingerprintToMetricCacheSize = flag . Int ( "storage.fingerprintToMetricCacheSizeBytes" , 25 * 1024 * 1024 , "The size in bytes for the fingerprint to metric index cache." )
labelNameToLabelValuesCacheSize = flag . Int ( "storage.labelNameToLabelValuesCacheSizeBytes" , 25 * 1024 * 1024 , "The size in bytes for the label name to label values index cache." )
labelPairToFingerprintsCacheSize = flag . Int ( "storage.labelPairToFingerprintsCacheSizeBytes" , 25 * 1024 * 1024 , "The size in bytes for the label pair to fingerprints index cache." )
2014-09-10 16:41:52 +00:00
fingerprintTimeRangeCacheSize = flag . Int ( "storage.fingerprintTimeRangeCacheSizeBytes" , 5 * 1024 * 1024 , "The size in bytes for the metric time range index cache." )
2014-09-09 13:13:07 +00:00
)
2014-08-21 20:06:11 +00:00
// 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 {
2014-09-10 16:41:52 +00:00
b . Put ( codec . CodableFingerprint ( fp ) , codec . CodableMetric ( m ) )
2014-08-21 20:06:11 +00:00
}
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 {
2014-09-10 16:41:52 +00:00
b . Delete ( codec . CodableFingerprint ( fp ) )
2014-08-21 20:06:11 +00:00
}
return i . Commit ( b )
}
// Lookup looks up a metric by fingerprint.
2014-09-10 16:41:52 +00:00
func ( i * FingerprintMetricIndex ) Lookup ( fp clientmodel . Fingerprint ) ( clientmodel . Metric , bool , error ) {
m := codec . CodableMetric { }
if ok , err := i . Get ( codec . CodableFingerprint ( fp ) , & m ) ; ! ok {
2014-08-21 20:06:11 +00:00
return nil , false , nil
} else if err != nil {
return nil , false , err
}
2014-09-10 16:41:52 +00:00
return clientmodel . Metric ( m ) , true , nil
2014-08-21 20:06:11 +00:00
}
// NewFingerprintMetricIndex returns a FingerprintMetricIndex
// object ready to use.
2014-09-10 16:41:52 +00:00
func NewFingerprintMetricIndex ( basePath string ) ( * FingerprintMetricIndex , error ) {
fingerprintToMetricDB , err := NewLevelDB ( LevelDBOptions {
Path : path . Join ( basePath , fingerprintToMetricDir ) ,
CacheSizeBytes : * fingerprintToMetricCacheSize ,
} )
if err != nil {
return nil , err
2014-08-21 20:06:11 +00:00
}
2014-09-10 16:41:52 +00:00
return & FingerprintMetricIndex {
KeyValueStore : fingerprintToMetricDB ,
} , nil
2014-08-21 20:06:11 +00:00
}
// 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 {
2014-09-10 16:41:52 +00:00
batch . Delete ( codec . CodableLabelName ( name ) )
2014-08-21 20:06:11 +00:00
} else {
2014-09-10 16:41:52 +00:00
batch . Put ( codec . CodableLabelName ( name ) , codec . CodableLabelValues ( values ) )
2014-08-21 20:06:11 +00:00
}
}
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 ) {
2014-09-10 16:41:52 +00:00
ok , err = i . Get ( codec . CodableLabelName ( l ) , ( * codec . CodableLabelValues ) ( & values ) )
2014-08-21 20:06:11 +00:00
if err != nil {
return nil , false , err
}
if ! ok {
return nil , false , nil
}
return values , true , nil
}
// NewLabelNameLabelValuesIndex returns a LabelNameLabelValuesIndex
// ready to use.
2014-09-10 16:41:52 +00:00
func NewLabelNameLabelValuesIndex ( basePath string ) ( * LabelNameLabelValuesIndex , error ) {
labelNameToLabelValuesDB , err := NewLevelDB ( LevelDBOptions {
Path : path . Join ( basePath , labelNameToLabelValuesDir ) ,
CacheSizeBytes : * labelNameToLabelValuesCacheSize ,
} )
if err != nil {
return nil , err
2014-08-21 20:06:11 +00:00
}
2014-09-10 16:41:52 +00:00
return & LabelNameLabelValuesIndex {
KeyValueStore : labelNameToLabelValuesDB ,
} , nil
2014-08-21 20:06:11 +00:00
}
// 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 {
2014-09-10 16:41:52 +00:00
batch . Delete ( codec . CodableLabelPair ( pair ) )
2014-08-21 20:06:11 +00:00
} else {
2014-09-10 16:41:52 +00:00
batch . Put ( codec . CodableLabelPair ( pair ) , codec . CodableFingerprints ( fps ) )
2014-08-21 20:06:11 +00:00
}
}
return i . Commit ( batch )
}
// Lookup looks up all fingerprints for a given label pair.
2014-09-10 16:41:52 +00:00
func ( i * LabelPairFingerprintIndex ) Lookup ( p metric . LabelPair ) ( fps clientmodel . Fingerprints , ok bool , err error ) {
ok , err = i . Get ( ( codec . CodableLabelPair ) ( p ) , ( * codec . CodableFingerprints ) ( & fps ) )
2014-08-21 20:06:11 +00:00
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.
2014-09-10 16:41:52 +00:00
func NewLabelPairFingerprintIndex ( basePath string ) ( * LabelPairFingerprintIndex , error ) {
labelPairToFingerprintsDB , err := NewLevelDB ( LevelDBOptions {
Path : path . Join ( basePath , labelPairToFingerprintsDir ) ,
CacheSizeBytes : * labelPairToFingerprintsCacheSize ,
} )
if err != nil {
return nil , err
2014-08-21 20:06:11 +00:00
}
2014-09-10 16:41:52 +00:00
return & LabelPairFingerprintIndex {
KeyValueStore : labelPairToFingerprintsDB ,
} , nil
2014-08-21 20:06:11 +00:00
}
2014-09-10 16:41:52 +00:00
// FingerprintTimeRangeIndex models a database tracking the time ranges
2014-08-21 20:06:11 +00:00
// of metrics by their fingerprints.
2014-09-10 16:41:52 +00:00
type FingerprintTimeRangeIndex struct {
2014-08-21 20:06:11 +00:00
KeyValueStore
}
// UnindexBatch unindexes a batch of fingerprints.
2014-09-10 16:41:52 +00:00
func ( i * FingerprintTimeRangeIndex ) UnindexBatch ( b FingerprintMetricMapping ) error {
2014-08-21 20:06:11 +00:00
batch := i . NewBatch ( )
for fp , _ := range b {
2014-09-10 16:41:52 +00:00
batch . Delete ( codec . CodableFingerprint ( fp ) )
2014-08-21 20:06:11 +00:00
}
return i . Commit ( batch )
}
// Has returns true if the given fingerprint is present.
2014-09-10 16:41:52 +00:00
func ( i * FingerprintTimeRangeIndex ) Has ( fp clientmodel . Fingerprint ) ( ok bool , err error ) {
return i . KeyValueStore . Has ( codec . CodableFingerprint ( fp ) )
2014-08-21 20:06:11 +00:00
}
2014-09-10 16:41:52 +00:00
// NewFingerprintTimeRangeIndex returns a FingerprintTimeRangeIndex object
2014-08-21 20:06:11 +00:00
// ready to use.
2014-09-10 16:41:52 +00:00
func NewFingerprintTimeRangeIndex ( basePath string ) ( * FingerprintTimeRangeIndex , error ) {
fingerprintTimeRangeDB , err := NewLevelDB ( LevelDBOptions {
Path : path . Join ( basePath , fingerprintTimeRangeDir ) ,
CacheSizeBytes : * fingerprintTimeRangeCacheSize ,
2014-09-09 13:13:07 +00:00
} )
if err != nil {
return nil , err
}
2014-09-10 16:41:52 +00:00
return & FingerprintTimeRangeIndex {
KeyValueStore : fingerprintTimeRangeDB ,
2014-09-09 13:13:07 +00:00
} , nil
}
2014-09-10 16:41:52 +00:00
func findUnindexed ( i * FingerprintTimeRangeIndex , b FingerprintMetricMapping ) ( FingerprintMetricMapping , error ) {
// TODO: Move up? Need to include fp->ts map?
2014-08-21 20:06:11 +00:00
out := FingerprintMetricMapping { }
for fp , m := range b {
has , err := i . Has ( fp )
if err != nil {
return nil , err
}
if ! has {
out [ fp ] = m
}
}
return out , nil
}
2014-09-10 16:41:52 +00:00
func findIndexed ( i * FingerprintTimeRangeIndex , b FingerprintMetricMapping ) ( FingerprintMetricMapping , error ) {
// TODO: Move up? Need to include fp->ts map?
2014-08-21 20:06:11 +00:00
out := FingerprintMetricMapping { }
for fp , m := range b {
has , err := i . Has ( fp )
if err != nil {
return nil , err
}
if has {
out [ fp ] = m
}
}
return out , nil
}
func extendLabelNameToLabelValuesIndex ( i * LabelNameLabelValuesIndex , b FingerprintMetricMapping ) ( LabelNameLabelValuesMapping , error ) {
2014-09-10 16:41:52 +00:00
// TODO: Move up? Need to include fp->ts map?
2014-08-21 20:06:11 +00:00
collection := map [ clientmodel . LabelName ] utility . Set { }
for _ , m := range b {
for l , v := range m {
set , ok := collection [ l ]
if ! ok {
baseValues , _ , err := i . Lookup ( l )
if err != nil {
return nil , err
}
set = utility . Set { }
for _ , baseValue := range baseValues {
set . Add ( baseValue )
}
collection [ l ] = set
}
set . Add ( v )
}
}
batch := LabelNameLabelValuesMapping { }
for l , set := range collection {
values := make ( clientmodel . LabelValues , 0 , len ( set ) )
for e := range set {
val := e . ( clientmodel . LabelValue )
values = append ( values , val )
}
batch [ l ] = values
}
return batch , nil
}
func reduceLabelNameToLabelValuesIndex ( i * LabelNameLabelValuesIndex , m LabelPairFingerprintsMapping ) ( LabelNameLabelValuesMapping , error ) {
2014-09-10 16:41:52 +00:00
// TODO: Move up? Need to include fp->ts map?
2014-08-21 20:06:11 +00:00
collection := map [ clientmodel . LabelName ] utility . Set { }
for lp , fps := range m {
if len ( fps ) != 0 {
continue
}
set , ok := collection [ lp . Name ]
if ! ok {
baseValues , _ , err := i . Lookup ( lp . Name )
if err != nil {
return nil , err
}
set = utility . Set { }
for _ , baseValue := range baseValues {
set . Add ( baseValue )
}
collection [ lp . Name ] = set
}
set . Remove ( lp . Value )
}
batch := LabelNameLabelValuesMapping { }
for l , set := range collection {
values := make ( clientmodel . LabelValues , 0 , len ( set ) )
for e := range set {
val := e . ( clientmodel . LabelValue )
values = append ( values , val )
}
batch [ l ] = values
}
return batch , nil
}
func extendLabelPairIndex ( i * LabelPairFingerprintIndex , b FingerprintMetricMapping , remove bool ) ( LabelPairFingerprintsMapping , error ) {
2014-09-10 16:41:52 +00:00
// TODO: Move up? Need to include fp->ts map?
2014-08-21 20:06:11 +00:00
collection := map [ metric . LabelPair ] utility . Set { }
for fp , m := range b {
for n , v := range m {
pair := metric . LabelPair {
Name : n ,
Value : v ,
}
set , ok := collection [ pair ]
if ! ok {
2014-09-10 16:41:52 +00:00
baseFps , _ , err := i . Lookup ( pair )
2014-08-21 20:06:11 +00:00
if err != nil {
return nil , err
}
set = utility . Set { }
for _ , baseFp := range baseFps {
set . Add ( baseFp )
}
collection [ pair ] = set
}
if remove {
set . Remove ( fp )
} else {
set . Add ( fp )
}
}
}
batch := LabelPairFingerprintsMapping { }
for pair , set := range collection {
fps := batch [ pair ]
for element := range set {
fp := element . ( clientmodel . Fingerprint )
fps = append ( fps , fp )
}
batch [ pair ] = fps
}
return batch , nil
}
2014-09-10 16:41:52 +00:00
// TODO: Move IndexMetrics and UndindexMetrics into storage.go.
/ *
2014-08-21 20:06:11 +00:00
// IndexMetrics adds the facets of all unindexed metrics found in the given
// FingerprintMetricMapping to the corresponding indices.
2014-09-09 13:13:07 +00:00
func ( i * diskIndexer ) IndexMetrics ( b FingerprintMetricMapping ) error {
2014-09-10 16:41:52 +00:00
unindexed , err := findUnindexed ( i . FingerprintTimeRange , b )
2014-08-21 20:06:11 +00:00
if err != nil {
return err
}
labelNames , err := extendLabelNameToLabelValuesIndex ( i . LabelNameToLabelValues , unindexed )
if err != nil {
return err
}
if err := i . LabelNameToLabelValues . IndexBatch ( labelNames ) ; err != nil {
return err
}
labelPairs , err := extendLabelPairIndex ( i . LabelPairToFingerprints , unindexed , false )
if err != nil {
return err
}
if err := i . LabelPairToFingerprints . IndexBatch ( labelPairs ) ; err != nil {
return err
}
if err := i . FingerprintToMetric . IndexBatch ( unindexed ) ; err != nil {
return err
}
2014-09-10 16:41:52 +00:00
return i . FingerprintTimeRange . IndexBatch ( unindexed )
2014-08-21 20:06:11 +00:00
}
2014-09-09 12:36:26 +00:00
// UnindexMetrics implements MetricIndexer.
2014-09-09 13:13:07 +00:00
func ( i * diskIndexer ) UnindexMetrics ( b FingerprintMetricMapping ) error {
2014-09-10 16:41:52 +00:00
indexed , err := findIndexed ( i . FingerprintTimeRange , b )
2014-08-21 20:06:11 +00:00
if err != nil {
return err
}
labelPairs , err := extendLabelPairIndex ( i . LabelPairToFingerprints , indexed , true )
if err != nil {
return err
}
if err := i . LabelPairToFingerprints . IndexBatch ( labelPairs ) ; err != nil {
return err
}
labelNames , err := reduceLabelNameToLabelValuesIndex ( i . LabelNameToLabelValues , labelPairs )
if err := i . LabelNameToLabelValues . IndexBatch ( labelNames ) ; err != nil {
return err
}
if err := i . FingerprintToMetric . UnindexBatch ( indexed ) ; err != nil {
return err
}
2014-09-10 16:41:52 +00:00
return i . FingerprintTimeRange . UnindexBatch ( indexed )
2014-09-09 12:36:26 +00:00
}
2014-09-10 16:41:52 +00:00
* /