@ -862,322 +862,16 @@ func (l *LevelDBMetricPersistence) GetMetricForFingerprint(f model.Fingerprint)
return
}
func ( l * LevelDBMetricPersistence ) GetBoundaryValues ( fp model . Fingerprint , i model . Interval , s StalenessPolicy ) ( open * model . Sample , end * model . Sample , err error ) {
begin := time . Now ( )
defer func ( ) {
duration := time . Since ( begin )
recordOutcome ( duration , err , map [ string ] string { operation : getBoundaryValues , result : success } , map [ string ] string { operation : getBoundaryValues , result : failure } )
} ( )
// XXX: Maybe we will want to emit incomplete sets?
open , err = l . GetValueAtTime ( fp , i . OldestInclusive , s )
if err != nil {
return
} else if open == nil {
return
}
end , err = l . GetValueAtTime ( fp , i . NewestInclusive , s )
if err != nil {
return
} else if end == nil {
open = nil
}
return
func ( l LevelDBMetricPersistence ) GetValueAtTime ( f model . Fingerprint , t time . Time ) ( samples [ ] model . SamplePair ) {
panic ( "Not implemented" )
}
func interpolate ( x1 , x2 time . Time , y1 , y2 float32 , e time . Time ) float32 {
yDelta := y2 - y1
xDelta := x2 . Sub ( x1 )
dDt := yDelta / float32 ( xDelta )
offset := float32 ( e . Sub ( x1 ) )
return y1 + ( offset * dDt )
func ( l LevelDBMetricPersistence ) GetBoundaryValues ( f model . Fingerprint , i model . Interval ) ( first [ ] model . SamplePair , second [ ] model . SamplePair ) {
panic ( "Not implemented" )
}
func ( l * LevelDBMetricPersistence ) GetValueAtTime ( fp model . Fingerprint , t time . Time , s StalenessPolicy ) ( sample * model . Sample , err error ) {
begin := time . Now ( )
defer func ( ) {
duration := time . Since ( begin )
recordOutcome ( duration , err , map [ string ] string { operation : getValueAtTime , result : success } , map [ string ] string { operation : getValueAtTime , result : failure } )
} ( )
// TODO: memoize/cache this or change the return type to metric.SamplePair.
m , err := l . GetMetricForFingerprint ( fp )
if err != nil {
return
}
// Candidate for Refactoring
k := & dto . SampleKey {
Fingerprint : fp . ToDTO ( ) ,
Timestamp : indexable . EncodeTime ( t ) ,
}
e , err := coding . NewProtocolBuffer ( k ) . Encode ( )
if err != nil {
return
}
iterator := l . metricSamples . NewIterator ( true )
defer iterator . Close ( )
if ! iterator . Seek ( e ) {
/ *
* Two cases for this :
* 1. ) Corruption in LevelDB .
* 2. ) Key seek after AND outside known range .
*
* Once a LevelDB iterator goes invalid , it cannot be recovered ; thusly ,
* we need to create a new in order to check if the last value in the
* database is sufficient for our purposes . This is , in all reality , a
* corner case but one that could bring down the system .
* /
iterator = l . metricSamples . NewIterator ( true )
defer iterator . Close ( )
if ! iterator . SeekToLast ( ) {
/ *
* For whatever reason , the LevelDB cannot be recovered .
* /
return
}
}
var (
firstKey * dto . SampleKey
firstValue * dto . SampleValueSeries
)
firstKey , err = extractSampleKey ( iterator )
if err != nil {
return
}
peekAhead := false
if ! fingerprintsEqual ( firstKey . Fingerprint , k . Fingerprint ) {
/ *
* This allows us to grab values for metrics if our request time is after
* the last recorded time subject to the staleness policy due to the nuances
* of LevelDB storage :
*
* # Assumptions :
* - K0 < K1 in terms of sorting .
* - T0 < T1 in terms of sorting .
*
* # Data
*
* K0 - T0
* K0 - T1
* K0 - T2
* K1 - T0
* K1 - T1
*
* # Scenario
* K0 - T3 , which does not exist , is requested . LevelDB will thusly seek to
* K1 - T1 , when K0 - T2 exists as a perfectly good candidate to check subject
* to the provided staleness policy and such .
* /
peekAhead = true
}
firstTime := indexable . DecodeTime ( firstKey . Timestamp )
if t . Before ( firstTime ) || peekAhead {
if ! iterator . Previous ( ) {
/ *
* Two cases for this :
* 1. ) Corruption in LevelDB .
* 2. ) Key seek before AND outside known range .
*
* This is an explicit validation to ensure that if no previous values for
* the series are found , the query aborts .
* /
return
}
var (
alternativeKey * dto . SampleKey
alternativeValue * dto . SampleValueSeries
)
alternativeKey , err = extractSampleKey ( iterator )
if err != nil {
return
}
if ! fingerprintsEqual ( alternativeKey . Fingerprint , k . Fingerprint ) {
return
}
/ *
* At this point , we found a previous value in the same series in the
* database . LevelDB originally seeked to the subsequent element given
* the key , but we need to consider this adjacency instead .
* /
alternativeTime := indexable . DecodeTime ( alternativeKey . Timestamp )
firstKey = alternativeKey
firstValue = alternativeValue
firstTime = alternativeTime
}
firstDelta := firstTime . Sub ( t )
if firstDelta < 0 {
firstDelta *= - 1
}
if firstDelta > s . DeltaAllowance {
return
}
firstValue , err = extractSampleValues ( iterator )
if err != nil {
return
}
sample = model . SampleFromDTO ( m , & t , firstValue )
if firstDelta == time . Duration ( 0 ) {
return
}
if ! iterator . Next ( ) {
/ *
* Two cases for this :
* 1. ) Corruption in LevelDB .
* 2. ) Key seek after AND outside known range .
*
* This means that there are no more values left in the storage ; and if this
* point is reached , we know that the one that has been found is within the
* allowed staleness limits .
* /
return
}
var secondKey * dto . SampleKey
secondKey , err = extractSampleKey ( iterator )
if err != nil {
return
}
if ! fingerprintsEqual ( secondKey . Fingerprint , k . Fingerprint ) {
return
} else {
/ *
* At this point , current entry in the database has the same key as the
* previous . For this reason , the validation logic will expect that the
* distance between the two points shall not exceed the staleness policy
* allowed limit to reduce interpolation errors .
*
* For this reason , the sample is reset in case of other subsequent
* validation behaviors .
* /
sample = nil
}
secondTime := indexable . DecodeTime ( secondKey . Timestamp )
totalDelta := secondTime . Sub ( firstTime )
if totalDelta > s . DeltaAllowance {
return
}
var secondValue * dto . SampleValueSeries
secondValue , err = extractSampleValues ( iterator )
if err != nil {
return
}
fValue := * firstValue . Value [ 0 ] . Value
sValue := * secondValue . Value [ 0 ] . Value
interpolated := interpolate ( firstTime , secondTime , fValue , sValue , t )
sampleValue := & dto . SampleValueSeries { }
sampleValue . Value = append ( sampleValue . Value , & dto . SampleValueSeries_Value { Value : & interpolated } )
sample = model . SampleFromDTO ( m , & t , sampleValue )
return
}
func ( l * LevelDBMetricPersistence ) GetRangeValues ( fp model . Fingerprint , i model . Interval ) ( v * model . SampleSet , err error ) {
begin := time . Now ( )
defer func ( ) {
duration := time . Since ( begin )
recordOutcome ( duration , err , map [ string ] string { operation : getRangeValues , result : success } , map [ string ] string { operation : getRangeValues , result : failure } )
} ( )
k := & dto . SampleKey {
Fingerprint : fp . ToDTO ( ) ,
Timestamp : indexable . EncodeTime ( i . OldestInclusive ) ,
}
e , err := coding . NewProtocolBuffer ( k ) . Encode ( )
if err != nil {
return
}
iterator := l . metricSamples . NewIterator ( true )
defer iterator . Close ( )
predicate := keyIsOlderThan ( i . NewestInclusive )
for valid := iterator . Seek ( e ) ; valid ; valid = iterator . Next ( ) {
retrievedKey := & dto . SampleKey { }
retrievedKey , err = extractSampleKey ( iterator )
if err != nil {
return
}
if predicate ( retrievedKey ) {
break
}
if ! fingerprintsEqual ( retrievedKey . Fingerprint , k . Fingerprint ) {
break
}
retrievedValue , err := extractSampleValues ( iterator )
if err != nil {
return nil , err
}
if v == nil {
// TODO: memoize/cache this or change the return type to metric.SamplePair.
m , err := l . GetMetricForFingerprint ( fp )
if err != nil {
return v , err
}
v = & model . SampleSet {
Metric : * m ,
}
}
v . Values = append ( v . Values , model . SamplePair {
Value : model . SampleValue ( * retrievedValue . Value [ 0 ] . Value ) ,
Timestamp : indexable . DecodeTime ( retrievedKey . Timestamp ) ,
} )
}
// XXX: We should not explicitly sort here but rather rely on the datastore.
// This adds appreciable overhead.
if v != nil {
sort . Sort ( v . Values )
}
return
func ( l * LevelDBMetricPersistence ) GetRangeValues ( f model . Fingerprint , i model . Interval ) ( samples [ ] model . SamplePair ) {
panic ( "Not implemented" )
}
type MetricKeyDecoder struct { }