2014-09-19 09:18:44 -07:00
// Copyright 2014 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2014-09-16 06:47:24 -07:00
// Package index provides a number of indexes backed by persistent key-value
// stores. The only supported implementation of a key-value store is currently
// goleveldb, but other implementations can easily be added.
2014-08-21 13:06:11 -07:00
package index
import (
2014-09-09 06:13:07 -07:00
"flag"
"path"
2014-08-21 13:06:11 -07:00
clientmodel "github.com/prometheus/client_golang/model"
2014-09-23 10:21:10 -07:00
"github.com/prometheus/prometheus/storage/local/codable"
2014-08-21 13:06:11 -07:00
"github.com/prometheus/prometheus/storage/metric"
)
2014-09-09 06:13:07 -07:00
const (
2014-09-10 09:41:52 -07:00
fingerprintToMetricDir = "archived_fingerprint_to_metric"
fingerprintTimeRangeDir = "archived_fingerprint_to_timerange"
2014-09-09 06:13:07 -07: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 09:41:52 -07:00
fingerprintTimeRangeCacheSize = flag . Int ( "storage.fingerprintTimeRangeCacheSizeBytes" , 5 * 1024 * 1024 , "The size in bytes for the metric time range index cache." )
2014-09-09 06:13:07 -07:00
)
2014-08-21 13:06:11 -07: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.
2014-09-16 06:47:24 -07:00
//
// This method is goroutine-safe, but note that no specific order of execution
// can be guaranteed (especially critical if IndexBatch and UnindexBatch are
// called concurrently).
2014-08-21 13:06:11 -07:00
func ( i * FingerprintMetricIndex ) IndexBatch ( mapping FingerprintMetricMapping ) error {
b := i . NewBatch ( )
for fp , m := range mapping {
2014-09-23 10:21:10 -07:00
b . Put ( codable . Fingerprint ( fp ) , codable . Metric ( m ) )
2014-08-21 13:06:11 -07:00
}
return i . Commit ( b )
}
// UnindexBatch unindexes a batch of mappings from fingerprints to metrics.
2014-09-16 06:47:24 -07:00
//
// This method is goroutine-safe, but note that no specific order of execution
// can be guaranteed (especially critical if IndexBatch and UnindexBatch are
// called concurrently).
2014-08-21 13:06:11 -07:00
func ( i * FingerprintMetricIndex ) UnindexBatch ( mapping FingerprintMetricMapping ) error {
b := i . NewBatch ( )
2014-09-16 06:47:24 -07:00
for fp := range mapping {
2014-09-23 10:21:10 -07:00
b . Delete ( codable . Fingerprint ( fp ) )
2014-08-21 13:06:11 -07:00
}
return i . Commit ( b )
}
2014-09-16 06:47:24 -07:00
// Lookup looks up a metric by fingerprint. Looking up a non-existing
// fingerprint is not an error. In that case, (nil, false, nil) is returned.
//
// This method is goroutine-safe.
2014-09-14 06:33:56 -07:00
func ( i * FingerprintMetricIndex ) Lookup ( fp clientmodel . Fingerprint ) ( metric clientmodel . Metric , ok bool , err error ) {
2014-09-23 10:21:10 -07:00
ok , err = i . Get ( codable . Fingerprint ( fp ) , ( * codable . Metric ) ( & metric ) )
2014-09-14 06:33:56 -07:00
return
2014-08-21 13:06:11 -07:00
}
2014-09-16 06:47:24 -07:00
// NewFingerprintMetricIndex returns a LevelDB-backed FingerprintMetricIndex
// ready to use.
2014-09-10 09:41:52 -07: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 13:06:11 -07:00
}
2014-09-10 09:41:52 -07:00
return & FingerprintMetricIndex {
KeyValueStore : fingerprintToMetricDB ,
} , nil
2014-08-21 13:06:11 -07:00
}
// LabelNameLabelValuesMapping is an in-memory map of label names to
// label values.
2014-09-23 10:21:10 -07:00
type LabelNameLabelValuesMapping map [ clientmodel . LabelName ] codable . LabelValueSet
2014-08-21 13:06:11 -07:00
2014-09-16 06:47:24 -07:00
// LabelNameLabelValuesIndex is a KeyValueStore that maps existing label names
// to all label values stored for that label name.
2014-08-21 13:06:11 -07:00
type LabelNameLabelValuesIndex struct {
KeyValueStore
}
2014-09-16 06:47:24 -07:00
// IndexBatch adds a batch of label name to label values mappings to the
// index. A mapping of a label name to an empty slice of label values results in
// a deletion of that mapping from the index.
//
// While this method is fundamentally goroutine-safe, note that the order of
2014-09-23 10:21:10 -07:00
// execution for multiple batches executed concurrently is undefined.
2014-08-21 13:06:11 -07:00
func ( i * LabelNameLabelValuesIndex ) IndexBatch ( b LabelNameLabelValuesMapping ) error {
batch := i . NewBatch ( )
for name , values := range b {
if len ( values ) == 0 {
2014-09-23 10:21:10 -07:00
if err := batch . Delete ( codable . LabelName ( name ) ) ; err != nil {
2014-09-16 06:47:24 -07:00
return err
}
2014-08-21 13:06:11 -07:00
} else {
2014-09-23 10:21:10 -07:00
if err := batch . Put ( codable . LabelName ( name ) , values ) ; err != nil {
2014-09-16 06:47:24 -07:00
return err
}
2014-08-21 13:06:11 -07:00
}
}
return i . Commit ( batch )
}
2014-09-16 06:47:24 -07:00
// Lookup looks up all label values for a given label name. Looking up a
// non-existing label name is not an error. In that case, (nil, false, nil) is
// returned.
//
// This method is goroutine-safe.
2014-08-21 13:06:11 -07:00
func ( i * LabelNameLabelValuesIndex ) Lookup ( l clientmodel . LabelName ) ( values clientmodel . LabelValues , ok bool , err error ) {
2014-09-23 10:21:10 -07:00
ok , err = i . Get ( codable . LabelName ( l ) , ( * codable . LabelValues ) ( & values ) )
2014-09-14 06:33:56 -07:00
return
}
2014-09-23 10:21:10 -07:00
// LookupSet looks up all label values for a given label name. Looking up a
// non-existing label name is not an error. In that case, (nil, false, nil) is
// returned.
2014-09-16 06:47:24 -07:00
//
2014-09-23 10:21:10 -07:00
// This method is goroutine-safe.
func ( i * LabelNameLabelValuesIndex ) LookupSet ( l clientmodel . LabelName ) ( values map [ clientmodel . LabelValue ] struct { } , ok bool , err error ) {
ok , err = i . Get ( codable . LabelName ( l ) , ( * codable . LabelValueSet ) ( & values ) )
if values == nil {
values = map [ clientmodel . LabelValue ] struct { } { }
2014-09-14 06:33:56 -07:00
}
2014-09-23 10:21:10 -07:00
return
2014-08-21 13:06:11 -07:00
}
2014-09-16 06:47:24 -07:00
// NewLabelNameLabelValuesIndex returns a LevelDB-backed
// LabelNameLabelValuesIndex ready to use.
2014-09-10 09:41:52 -07: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 13:06:11 -07:00
}
2014-09-10 09:41:52 -07:00
return & LabelNameLabelValuesIndex {
KeyValueStore : labelNameToLabelValuesDB ,
} , nil
2014-08-21 13:06:11 -07:00
}
// LabelPairFingerprintsMapping is an in-memory map of label pairs to
// fingerprints.
2014-09-23 10:21:10 -07:00
type LabelPairFingerprintsMapping map [ metric . LabelPair ] codable . FingerprintSet
2014-08-21 13:06:11 -07:00
2014-09-16 06:47:24 -07:00
// LabelPairFingerprintIndex is a KeyValueStore that maps existing label pairs
// to the fingerprints of all metrics containing those label pairs.
2014-08-21 13:06:11 -07:00
type LabelPairFingerprintIndex struct {
KeyValueStore
}
2014-09-16 06:47:24 -07:00
// IndexBatch indexes a batch of mappings from label pairs to fingerprints. A
// mapping to an empty slice of fingerprints results in deletion of that mapping
// from the index.
//
// While this method is fundamentally goroutine-safe, note that the order of
2014-09-23 10:21:10 -07:00
// execution for multiple batches executed concurrently is undefined.
2014-08-21 13:06:11 -07:00
func ( i * LabelPairFingerprintIndex ) IndexBatch ( m LabelPairFingerprintsMapping ) error {
batch := i . NewBatch ( )
for pair , fps := range m {
if len ( fps ) == 0 {
2014-09-23 10:21:10 -07:00
batch . Delete ( codable . LabelPair ( pair ) )
2014-08-21 13:06:11 -07:00
} else {
2014-09-23 10:21:10 -07:00
batch . Put ( codable . LabelPair ( pair ) , fps )
2014-08-21 13:06:11 -07:00
}
}
return i . Commit ( batch )
}
2014-09-16 06:47:24 -07:00
// Lookup looks up all fingerprints for a given label pair. Looking up a
// non-existing label pair is not an error. In that case, (nil, false, nil) is
// returned.
//
// This method is goroutine-safe.
2014-09-10 09:41:52 -07:00
func ( i * LabelPairFingerprintIndex ) Lookup ( p metric . LabelPair ) ( fps clientmodel . Fingerprints , ok bool , err error ) {
2014-09-23 10:21:10 -07:00
ok , err = i . Get ( ( codable . LabelPair ) ( p ) , ( * codable . Fingerprints ) ( & fps ) )
2014-09-14 06:33:56 -07:00
return
}
2014-09-23 10:21:10 -07:00
// LookupSet looks up all fingerprints for a given label pair. Looking up a
// non-existing label pair is not an error. In that case, (nil, false, nil) is
// returned.
2014-09-16 06:47:24 -07:00
//
2014-09-23 10:21:10 -07:00
// This method is goroutine-safe.
func ( i * LabelPairFingerprintIndex ) LookupSet ( p metric . LabelPair ) ( fps map [ clientmodel . Fingerprint ] struct { } , ok bool , err error ) {
ok , err = i . Get ( ( codable . LabelPair ) ( p ) , ( * codable . FingerprintSet ) ( & fps ) )
if fps == nil {
fps = map [ clientmodel . Fingerprint ] struct { } { }
2014-09-14 06:33:56 -07:00
}
2014-09-23 10:21:10 -07:00
return
2014-08-21 13:06:11 -07:00
}
2014-09-16 06:47:24 -07:00
// NewLabelPairFingerprintIndex returns a LevelDB-backed
// LabelPairFingerprintIndex ready to use.
2014-09-10 09:41:52 -07: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 13:06:11 -07:00
}
2014-09-10 09:41:52 -07:00
return & LabelPairFingerprintIndex {
KeyValueStore : labelPairToFingerprintsDB ,
} , nil
2014-08-21 13:06:11 -07:00
}
2014-09-10 09:41:52 -07:00
// FingerprintTimeRangeIndex models a database tracking the time ranges
2014-08-21 13:06:11 -07:00
// of metrics by their fingerprints.
2014-09-10 09:41:52 -07:00
type FingerprintTimeRangeIndex struct {
2014-08-21 13:06:11 -07:00
KeyValueStore
}
2014-09-16 06:47:24 -07:00
// Lookup returns the time range for the given fingerprint. Looking up a
// non-existing fingerprint is not an error. In that case, (0, 0, false, nil) is
// returned.
//
// This method is goroutine-safe.
2014-09-14 06:33:56 -07:00
func ( i * FingerprintTimeRangeIndex ) Lookup ( fp clientmodel . Fingerprint ) ( firstTime , lastTime clientmodel . Timestamp , ok bool , err error ) {
2014-09-23 10:21:10 -07:00
var tr codable . TimeRange
ok , err = i . Get ( codable . Fingerprint ( fp ) , & tr )
2014-09-14 06:33:56 -07:00
return tr . First , tr . Last , ok , err
2014-08-21 13:06:11 -07:00
}
// Has returns true if the given fingerprint is present.
2014-09-16 06:47:24 -07:00
//
// This method is goroutine-safe.
2014-09-10 09:41:52 -07:00
func ( i * FingerprintTimeRangeIndex ) Has ( fp clientmodel . Fingerprint ) ( ok bool , err error ) {
2014-09-23 10:21:10 -07:00
return i . KeyValueStore . Has ( codable . Fingerprint ( fp ) )
2014-08-21 13:06:11 -07:00
}
2014-09-16 06:47:24 -07:00
// NewFingerprintTimeRangeIndex returns a LevelDB-backed
// FingerprintTimeRangeIndex ready to use.
2014-09-10 09:41:52 -07:00
func NewFingerprintTimeRangeIndex ( basePath string ) ( * FingerprintTimeRangeIndex , error ) {
fingerprintTimeRangeDB , err := NewLevelDB ( LevelDBOptions {
Path : path . Join ( basePath , fingerprintTimeRangeDir ) ,
CacheSizeBytes : * fingerprintTimeRangeCacheSize ,
2014-09-09 06:13:07 -07:00
} )
if err != nil {
return nil , err
}
2014-09-10 09:41:52 -07:00
return & FingerprintTimeRangeIndex {
KeyValueStore : fingerprintTimeRangeDB ,
2014-09-09 06:13:07 -07:00
} , nil
}