213 lines
4.9 KiB
Go
213 lines
4.9 KiB
Go
|
// 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/golang/glog"
|
||
|
|
||
|
"github.com/prometheus/prometheus/storage/raw/leveldb"
|
||
|
|
||
|
dto "github.com/prometheus/prometheus/model/generated"
|
||
|
)
|
||
|
|
||
|
type iteratorSeekerState struct {
|
||
|
// Immutable State
|
||
|
i leveldb.Iterator
|
||
|
|
||
|
obj *SampleKey
|
||
|
|
||
|
first, last *SampleKey
|
||
|
|
||
|
dtoSampleKeys *dtoSampleKeyList
|
||
|
sampleKeys *sampleKeyList
|
||
|
|
||
|
// Mutable State
|
||
|
iteratorInvalid bool
|
||
|
seriesOperable bool
|
||
|
err error
|
||
|
|
||
|
key *SampleKey
|
||
|
keyDto *dto.SampleKey
|
||
|
}
|
||
|
|
||
|
// iteratorSeeker is a function that models a state machine state and
|
||
|
// is responsible for choosing the subsequent state given the present
|
||
|
// disposition.
|
||
|
//
|
||
|
// It returns the next state or nil if no remaining transition is possible.
|
||
|
// It returns an error if one occurred and finally a truth value indicating
|
||
|
// whether the current iterator state is usable and whether it can proceed with
|
||
|
// the current fingerprint.
|
||
|
type iteratorSeeker func() iteratorSeeker
|
||
|
|
||
|
func (s *iteratorSeekerState) initialize() iteratorSeeker {
|
||
|
s.key, _ = s.sampleKeys.Get()
|
||
|
s.keyDto, _ = s.dtoSampleKeys.Get()
|
||
|
|
||
|
return s.start
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) destroy() iteratorSeeker {
|
||
|
s.sampleKeys.Give(s.key)
|
||
|
s.dtoSampleKeys.Give(s.keyDto)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) start() iteratorSeeker {
|
||
|
switch {
|
||
|
case s.obj.Fingerprint.Less(s.first.Fingerprint):
|
||
|
// The fingerprint does not exist in the database.
|
||
|
return s.destroy
|
||
|
|
||
|
case s.last.Fingerprint.Less(s.obj.Fingerprint):
|
||
|
// The fingerprint does not exist in the database.
|
||
|
return s.destroy
|
||
|
|
||
|
case s.obj.Fingerprint.Equal(s.first.Fingerprint) && s.obj.FirstTimestamp.Before(s.first.FirstTimestamp):
|
||
|
// The fingerprint is the first fingerprint, but we've requested a value
|
||
|
// before what exists in the database.
|
||
|
return s.seekBeginning
|
||
|
|
||
|
case s.last.Before(s.obj.Fingerprint, s.obj.FirstTimestamp):
|
||
|
// The requested time for work is after the last sample in the database; we
|
||
|
// can't do anything!
|
||
|
return s.destroy
|
||
|
|
||
|
default:
|
||
|
return s.initialSeek
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) seekBeginning() iteratorSeeker {
|
||
|
s.i.SeekToFirst()
|
||
|
if !s.i.Valid() {
|
||
|
s.err = s.i.Error()
|
||
|
// If we can't seek to the beginning, there isn't any hope for us.
|
||
|
glog.Warning("iterator went bad: %s", s.err)
|
||
|
s.iteratorInvalid = true
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
return s.initialMatchFingerprint
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) initialSeek() iteratorSeeker {
|
||
|
s.obj.Dump(s.keyDto)
|
||
|
|
||
|
s.i.Seek(s.keyDto)
|
||
|
if !s.i.Valid() {
|
||
|
s.err = s.i.Error()
|
||
|
glog.Warningf("iterator went bad %s", s.err)
|
||
|
s.iteratorInvalid = true
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
return s.initialMatchFingerprint
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) initialMatchFingerprint() iteratorSeeker {
|
||
|
if err := s.i.Key(s.keyDto); err != nil {
|
||
|
s.err = err
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
s.key.Load(s.keyDto)
|
||
|
|
||
|
switch {
|
||
|
case s.obj.Fingerprint.Less(s.key.Fingerprint):
|
||
|
return s.initialFingerprintOvershot
|
||
|
|
||
|
case s.key.Fingerprint.Less(s.obj.Fingerprint):
|
||
|
panic("violated invariant")
|
||
|
|
||
|
default:
|
||
|
return s.initialMatchTime
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) initialFingerprintOvershot() iteratorSeeker {
|
||
|
s.i.Previous()
|
||
|
if !s.i.Valid() {
|
||
|
glog.Warningf("Could not backtrack for %s", s)
|
||
|
panic("violated invariant")
|
||
|
}
|
||
|
|
||
|
if err := s.i.Key(s.keyDto); err != nil {
|
||
|
s.err = err
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
s.key.Load(s.keyDto)
|
||
|
|
||
|
if !s.key.Fingerprint.Equal(s.obj.Fingerprint) {
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
return s.initialMatchTime
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) initialMatchTime() iteratorSeeker {
|
||
|
switch {
|
||
|
case s.key.MayContain(s.obj.FirstTimestamp):
|
||
|
s.seriesOperable = true
|
||
|
return s.destroy
|
||
|
|
||
|
case s.key.Equal(s.first), s.obj.FirstTimestamp.Equal(s.key.FirstTimestamp):
|
||
|
s.seriesOperable = true
|
||
|
return s.destroy
|
||
|
|
||
|
case s.obj.FirstTimestamp.Before(s.key.FirstTimestamp):
|
||
|
return s.reCue
|
||
|
|
||
|
default:
|
||
|
panic("violated invariant " + fmt.Sprintln(s.obj, s.key))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) reCue() iteratorSeeker {
|
||
|
s.i.Previous()
|
||
|
if !s.i.Valid() {
|
||
|
glog.Warningf("Could not backtrack for %s", s)
|
||
|
panic("violated invariant")
|
||
|
}
|
||
|
|
||
|
if err := s.i.Key(s.keyDto); err != nil {
|
||
|
s.err = err
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
s.key.Load(s.keyDto)
|
||
|
|
||
|
if !s.key.Fingerprint.Equal(s.obj.Fingerprint) {
|
||
|
return s.fastForward
|
||
|
}
|
||
|
|
||
|
s.seriesOperable = true
|
||
|
return s.destroy
|
||
|
}
|
||
|
|
||
|
func (s *iteratorSeekerState) fastForward() iteratorSeeker {
|
||
|
s.i.Next()
|
||
|
if !s.i.Valid() {
|
||
|
glog.Warningf("Could not fast-forward for %s", s)
|
||
|
panic("violated invariant")
|
||
|
}
|
||
|
|
||
|
s.seriesOperable = true
|
||
|
return s.destroy
|
||
|
}
|