2013-02-08 17:03:26 +00:00
// Copyright 2013 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.
package metric
import (
"fmt"
"github.com/prometheus/prometheus/coding"
"github.com/prometheus/prometheus/coding/indexable"
"github.com/prometheus/prometheus/model"
dto "github.com/prometheus/prometheus/model/generated"
2013-03-25 09:24:59 +00:00
"github.com/prometheus/prometheus/storage/raw/leveldb"
2013-02-08 17:03:26 +00:00
"time"
)
// diskFrontier describes an on-disk store of series to provide a
// representation of the known keyspace and time series values available.
//
// This is used to reduce the burden associated with LevelDB iterator
// management.
type diskFrontier struct {
firstFingerprint model . Fingerprint
firstSupertime time . Time
lastFingerprint model . Fingerprint
lastSupertime time . Time
}
2013-04-01 11:22:38 +00:00
func ( f diskFrontier ) String ( ) string {
2013-02-08 17:03:26 +00:00
return fmt . Sprintf ( "diskFrontier from %s at %s to %s at %s" , f . firstFingerprint . ToRowKey ( ) , f . firstSupertime , f . lastFingerprint . ToRowKey ( ) , f . lastSupertime )
}
2013-04-01 11:22:38 +00:00
func ( f diskFrontier ) ContainsFingerprint ( fingerprint model . Fingerprint ) bool {
2013-03-15 01:29:42 +00:00
return ! ( fingerprint . Less ( f . firstFingerprint ) || f . lastFingerprint . Less ( fingerprint ) )
2013-03-11 21:59:28 +00:00
}
2013-03-25 09:24:59 +00:00
func newDiskFrontier ( i leveldb . Iterator ) ( d * diskFrontier , err error ) {
if ! i . SeekToLast ( ) || i . Key ( ) == nil {
2013-02-08 17:03:26 +00:00
return
}
2013-04-01 11:22:38 +00:00
2013-02-08 17:03:26 +00:00
lastKey , err := extractSampleKey ( i )
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
2013-04-01 11:22:38 +00:00
if ! i . SeekToFirst ( ) || i . Key ( ) == nil {
return
}
2013-02-08 17:03:26 +00:00
firstKey , err := extractSampleKey ( i )
if i . Key ( ) == nil {
return
}
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
d = & diskFrontier { }
2013-04-21 17:16:15 +00:00
d . firstFingerprint = firstKey . Fingerprint
d . firstSupertime = firstKey . FirstTimestamp
d . lastFingerprint = lastKey . Fingerprint
d . lastSupertime = lastKey . FirstTimestamp
2013-02-08 17:03:26 +00:00
return
}
// seriesFrontier represents the valid seek frontier for a given series.
type seriesFrontier struct {
firstSupertime time . Time
lastSupertime time . Time
lastTime time . Time
}
func ( f seriesFrontier ) String ( ) string {
return fmt . Sprintf ( "seriesFrontier from %s to %s at %s" , f . firstSupertime , f . lastSupertime , f . lastTime )
}
// newSeriesFrontier furnishes a populated diskFrontier for a given
// fingerprint. A nil diskFrontier will be returned if the series cannot
// be found in the store.
2013-03-25 09:24:59 +00:00
func newSeriesFrontier ( f model . Fingerprint , d diskFrontier , i leveldb . Iterator ) ( s * seriesFrontier , err error ) {
2013-02-08 17:03:26 +00:00
var (
lowerSeek = firstSupertime
upperSeek = lastSupertime
)
2013-04-01 11:22:38 +00:00
// If the diskFrontier for this iterator says that the candidate fingerprint
// is outside of its seeking domain, there is no way that a seriesFrontier
// could be materialized. Simply bail.
if ! d . ContainsFingerprint ( f ) {
return
}
2013-02-08 17:03:26 +00:00
// If we are either the first or the last key in the database, we need to use
// pessimistic boundary frontiers.
if f . Equal ( d . firstFingerprint ) {
lowerSeek = indexable . EncodeTime ( d . firstSupertime )
}
if f . Equal ( d . lastFingerprint ) {
upperSeek = indexable . EncodeTime ( d . lastSupertime )
}
2013-04-21 17:16:15 +00:00
// TODO: Convert this to SampleKey.ToPartialDTO.
2013-02-08 17:03:26 +00:00
key := & dto . SampleKey {
Fingerprint : f . ToDTO ( ) ,
Timestamp : upperSeek ,
}
2013-04-05 11:07:13 +00:00
raw , err := coding . NewProtocolBuffer ( key ) . Encode ( )
2013-02-08 17:03:26 +00:00
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
i . Seek ( raw )
if i . Key ( ) == nil {
return
}
retrievedKey , err := extractSampleKey ( i )
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
2013-04-21 17:16:15 +00:00
retrievedFingerprint := retrievedKey . Fingerprint
2013-02-08 17:03:26 +00:00
// The returned fingerprint may not match if the original seek key lives
// outside of a metric's frontier. This is probable, for we are seeking to
// to the maximum allowed time, which could advance us to the next
// fingerprint.
//
//
if ! retrievedFingerprint . Equal ( f ) {
2013-03-25 09:24:59 +00:00
i . Previous ( )
2013-02-08 17:03:26 +00:00
retrievedKey , err = extractSampleKey ( i )
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
2013-04-21 17:16:15 +00:00
retrievedFingerprint := retrievedKey . Fingerprint
2013-02-08 17:03:26 +00:00
// If the previous key does not match, we know that the requested
// fingerprint does not live in the database.
if ! retrievedFingerprint . Equal ( f ) {
return
}
}
s = & seriesFrontier {
2013-04-21 17:16:15 +00:00
lastSupertime : retrievedKey . FirstTimestamp ,
lastTime : retrievedKey . LastTimestamp ,
2013-02-08 17:03:26 +00:00
}
key . Timestamp = lowerSeek
2013-04-05 11:07:13 +00:00
raw , err = coding . NewProtocolBuffer ( key ) . Encode ( )
2013-02-08 17:03:26 +00:00
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
i . Seek ( raw )
retrievedKey , err = extractSampleKey ( i )
if err != nil {
2013-03-01 17:51:36 +00:00
panic ( err )
2013-02-08 17:03:26 +00:00
}
2013-04-21 17:16:15 +00:00
retrievedFingerprint = retrievedKey . Fingerprint
2013-02-08 17:03:26 +00:00
2013-04-21 17:16:15 +00:00
s . firstSupertime = retrievedKey . FirstTimestamp
2013-02-08 17:03:26 +00:00
return
}