@ -16,6 +16,7 @@ package agent
import (
import (
"sync"
"sync"
"github.com/prometheus/prometheus/model/exemplar"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/tsdb/chunks"
"github.com/prometheus/prometheus/tsdb/chunks"
)
)
@ -89,10 +90,11 @@ func (m seriesHashmap) Delete(hash uint64, ref chunks.HeadSeriesRef) {
// Filling the padded space with the maps was profiled to be slower -
// Filling the padded space with the maps was profiled to be slower -
// likely due to the additional pointer dereferences.
// likely due to the additional pointer dereferences.
type stripeSeries struct {
type stripeSeries struct {
size int
size int
series [ ] map [ chunks . HeadSeriesRef ] * memSeries
series [ ] map [ chunks . HeadSeriesRef ] * memSeries
hashes [ ] seriesHashmap
hashes [ ] seriesHashmap
locks [ ] stripeLock
exemplars [ ] map [ chunks . HeadSeriesRef ] * exemplar . Exemplar
locks [ ] stripeLock
gcMut sync . Mutex
gcMut sync . Mutex
}
}
@ -105,10 +107,11 @@ type stripeLock struct {
func newStripeSeries ( stripeSize int ) * stripeSeries {
func newStripeSeries ( stripeSize int ) * stripeSeries {
s := & stripeSeries {
s := & stripeSeries {
size : stripeSize ,
size : stripeSize ,
series : make ( [ ] map [ chunks . HeadSeriesRef ] * memSeries , stripeSize ) ,
series : make ( [ ] map [ chunks . HeadSeriesRef ] * memSeries , stripeSize ) ,
hashes : make ( [ ] seriesHashmap , stripeSize ) ,
hashes : make ( [ ] seriesHashmap , stripeSize ) ,
locks : make ( [ ] stripeLock , stripeSize ) ,
exemplars : make ( [ ] map [ chunks . HeadSeriesRef ] * exemplar . Exemplar , stripeSize ) ,
locks : make ( [ ] stripeLock , stripeSize ) ,
}
}
for i := range s . series {
for i := range s . series {
s . series [ i ] = map [ chunks . HeadSeriesRef ] * memSeries { }
s . series [ i ] = map [ chunks . HeadSeriesRef ] * memSeries { }
@ -116,6 +119,9 @@ func newStripeSeries(stripeSize int) *stripeSeries {
for i := range s . hashes {
for i := range s . hashes {
s . hashes [ i ] = seriesHashmap { }
s . hashes [ i ] = seriesHashmap { }
}
}
for i := range s . exemplars {
s . exemplars [ i ] = map [ chunks . HeadSeriesRef ] * exemplar . Exemplar { }
}
return s
return s
}
}
@ -154,6 +160,10 @@ func (s *stripeSeries) GC(mint int64) map[chunks.HeadSeriesRef]struct{} {
delete ( s . series [ refLock ] , series . ref )
delete ( s . series [ refLock ] , series . ref )
s . hashes [ hashLock ] . Delete ( hash , series . ref )
s . hashes [ hashLock ] . Delete ( hash , series . ref )
// Since the series is gone, we'll also delete
// the latest stored exemplar.
delete ( s . exemplars [ refLock ] , series . ref )
if hashLock != refLock {
if hashLock != refLock {
s . locks [ refLock ] . Unlock ( )
s . locks [ refLock ] . Unlock ( )
}
}
@ -201,3 +211,24 @@ func (s *stripeSeries) Set(hash uint64, series *memSeries) {
s . hashes [ hashLock ] . Set ( hash , series )
s . hashes [ hashLock ] . Set ( hash , series )
s . locks [ hashLock ] . Unlock ( )
s . locks [ hashLock ] . Unlock ( )
}
}
func ( s * stripeSeries ) GetLatestExemplar ( ref chunks . HeadSeriesRef ) * exemplar . Exemplar {
i := uint64 ( ref ) & uint64 ( s . size - 1 )
s . locks [ i ] . RLock ( )
exemplar := s . exemplars [ i ] [ ref ]
s . locks [ i ] . RUnlock ( )
return exemplar
}
func ( s * stripeSeries ) SetLatestExemplar ( ref chunks . HeadSeriesRef , exemplar * exemplar . Exemplar ) {
i := uint64 ( ref ) & uint64 ( s . size - 1 )
// Make sure that's a valid series id and record its latest exemplar
s . locks [ i ] . Lock ( )
if s . series [ i ] [ ref ] != nil {
s . exemplars [ i ] [ ref ] = exemplar
}
s . locks [ i ] . Unlock ( )
}