@ -846,16 +846,17 @@ func (a *headAppender) Commit() (err error) {
// number of samples rejected due to: out of bounds: with t < minValidTime (OOO support disabled)
floatOOBRejected int
inOrderMint int64 = math . MaxInt64
inOrderMaxt int64 = math . MinInt64
ooomint int64 = math . MaxInt64
ooomaxt int64 = math . MinInt64
wblSamples [ ] record . RefSample
oooMmapMarkers map [ chunks . HeadSeriesRef ] chunks . ChunkDiskMapperRef
oooRecords [ ] [ ] byte
oooCapMax = a . head . opts . OutOfOrderCapMax . Load ( )
series * memSeries
appendChunkOpts = chunkOpts {
inOrderMint int64 = math . MaxInt64
inOrderMaxt int64 = math . MinInt64
oooMinT int64 = math . MaxInt64
oooMaxT int64 = math . MinInt64
wblSamples [ ] record . RefSample
oooMmapMarkers map [ chunks . HeadSeriesRef ] [ ] chunks . ChunkDiskMapperRef
oooMmapMarkersCount int
oooRecords [ ] [ ] byte
oooCapMax = a . head . opts . OutOfOrderCapMax . Load ( )
series * memSeries
appendChunkOpts = chunkOpts {
chunkDiskMapper : a . head . chunkDiskMapper ,
chunkRange : a . head . chunkRange . Load ( ) ,
samplesPerChunk : a . head . opts . SamplesPerChunk ,
@ -872,6 +873,7 @@ func (a *headAppender) Commit() (err error) {
// WBL is not enabled. So no need to collect.
wblSamples = nil
oooMmapMarkers = nil
oooMmapMarkersCount = 0
return
}
// The m-map happens before adding a new sample. So we collect
@ -880,12 +882,14 @@ func (a *headAppender) Commit() (err error) {
// WBL Before this Commit(): [old samples before this commit for chunk 1]
// WBL After this Commit(): [old samples before this commit for chunk 1][new samples in this commit for chunk 1]mmapmarker1[samples for chunk 2]mmapmarker2[samples for chunk 3]
if oooMmapMarkers != nil {
markers := make ( [ ] record . RefMmapMarker , 0 , len ( oooMmapMarkers ) )
for ref , mmapRef := range oooMmapMarkers {
markers = append ( markers , record . RefMmapMarker {
Ref : ref ,
MmapRef : mmapRef ,
} )
markers := make ( [ ] record . RefMmapMarker , 0 , oooMmapMarkersCount )
for ref , mmapRefs := range oooMmapMarkers {
for _ , mmapRef := range mmapRefs {
markers = append ( markers , record . RefMmapMarker {
Ref : ref ,
MmapRef : mmapRef ,
} )
}
}
r := enc . MmapMarkers ( markers , a . head . getBytesBuffer ( ) )
oooRecords = append ( oooRecords , r )
@ -928,32 +932,39 @@ func (a *headAppender) Commit() (err error) {
case oooSample :
// Sample is OOO and OOO handling is enabled
// and the delta is within the OOO tolerance.
var mmapRef chunks . ChunkDiskMapperRef
ok , chunkCreated , mmapRef = series . insert ( s . T , s . V , a . head . chunkDiskMapper , oooCapMax )
var mmapRefs [ ] chunks . ChunkDiskMapperRef
ok , chunkCreated , mmapRefs = series . insert ( s . T , s . V , a . head . chunkDiskMapper , oooCapMax )
if chunkCreated {
r , ok := oooMmapMarkers [ series . ref ]
if ! ok || r != 0 {
if ! ok || r != nil {
// !ok means there are no markers collected for these samples yet. So we first flush the samples
// before setting this m-map marker.
// r != 0 means we have already m-mapped a chunk for this series in the same Commit().
// r != nil means we have already m-mapped a chunk for this series in the same Commit().
// Hence, before we m-map again, we should add the samples and m-map markers
// seen till now to the WBL records.
collectOOORecords ( )
}
if oooMmapMarkers == nil {
oooMmapMarkers = make ( map [ chunks . HeadSeriesRef ] chunks . ChunkDiskMapperRef )
oooMmapMarkers = make ( map [ chunks . HeadSeriesRef ] [ ] chunks . ChunkDiskMapperRef )
}
if len ( mmapRefs ) > 0 {
oooMmapMarkers [ series . ref ] = mmapRefs
oooMmapMarkersCount += len ( mmapRefs )
} else {
// No chunk was written to disk, so we need to set an initial marker for this series.
oooMmapMarkers [ series . ref ] = [ ] chunks . ChunkDiskMapperRef { 0 }
oooMmapMarkersCount ++
}
oooMmapMarkers [ series . ref ] = mmapRef
}
if ok {
wblSamples = append ( wblSamples , s )
if s . T < ooomint {
ooomint = s . T
if s . T < oooMinT {
oooMinT = s . T
}
if s . T > ooomaxt {
ooomaxt = s . T
if s . T > oooMaxT {
oooMaxT = s . T
}
floatOOOAccepted ++
} else {
@ -1053,7 +1064,7 @@ func (a *headAppender) Commit() (err error) {
a . head . metrics . samplesAppended . WithLabelValues ( sampleMetricTypeHistogram ) . Add ( float64 ( histogramsAppended ) )
a . head . metrics . outOfOrderSamplesAppended . WithLabelValues ( sampleMetricTypeFloat ) . Add ( float64 ( floatOOOAccepted ) )
a . head . updateMinMaxTime ( inOrderMint , inOrderMaxt )
a . head . updateMinOOOMaxOOOTime ( ooomint , ooomaxt )
a . head . updateMinOOOMaxOOOTime ( oooMinT , oooMaxT )
collectOOORecords ( )
if a . head . wbl != nil {
@ -1069,14 +1080,14 @@ func (a *headAppender) Commit() (err error) {
}
// insert is like append, except it inserts. Used for OOO samples.
func ( s * memSeries ) insert ( t int64 , v float64 , chunkDiskMapper * chunks . ChunkDiskMapper , oooCapMax int64 ) ( inserted , chunkCreated bool , mmapRef chunks . ChunkDiskMapperRef ) {
func ( s * memSeries ) insert ( t int64 , v float64 , chunkDiskMapper * chunks . ChunkDiskMapper , oooCapMax int64 ) ( inserted , chunkCreated bool , mmapRefs [ ] chunks . ChunkDiskMapperRef ) {
if s . ooo == nil {
s . ooo = & memSeriesOOOFields { }
}
c := s . ooo . oooHeadChunk
if c == nil || c . chunk . NumSamples ( ) == int ( oooCapMax ) {
// Note: If no new samples come in then we rely on compaction to clean up stale in-memory OOO chunks.
c , mmapRef = s . cutNewOOOHeadChunk ( t , chunkDiskMapper )
c , mmapRefs = s . cutNewOOOHeadChunk ( t , chunkDiskMapper )
chunkCreated = true
}
@ -1089,7 +1100,7 @@ func (s *memSeries) insert(t int64, v float64, chunkDiskMapper *chunks.ChunkDisk
c . maxTime = t
}
}
return ok , chunkCreated , mmapRef
return ok , chunkCreated , mmapRefs
}
// chunkOpts are chunk-level options that are passed when appending to a memSeries.
@ -1431,7 +1442,7 @@ func (s *memSeries) cutNewHeadChunk(mint int64, e chunkenc.Encoding, chunkRange
// cutNewOOOHeadChunk cuts a new OOO chunk and m-maps the old chunk.
// The caller must ensure that s.ooo is not nil.
func ( s * memSeries ) cutNewOOOHeadChunk ( mint int64 , chunkDiskMapper * chunks . ChunkDiskMapper ) ( * oooHeadChunk , chunks . ChunkDiskMapperRef ) {
func ( s * memSeries ) cutNewOOOHeadChunk ( mint int64 , chunkDiskMapper * chunks . ChunkDiskMapper ) ( * oooHeadChunk , [ ] chunks . ChunkDiskMapperRef ) {
ref := s . mmapCurrentOOOHeadChunk ( chunkDiskMapper )
s . ooo . oooHeadChunk = & oooHeadChunk {
@ -1443,21 +1454,29 @@ func (s *memSeries) cutNewOOOHeadChunk(mint int64, chunkDiskMapper *chunks.Chunk
return s . ooo . oooHeadChunk , ref
}
func ( s * memSeries ) mmapCurrentOOOHeadChunk ( chunkDiskMapper * chunks . ChunkDiskMapper ) chunks . ChunkDiskMapperRef {
func ( s * memSeries ) mmapCurrentOOOHeadChunk ( chunkDiskMapper * chunks . ChunkDiskMapper ) [ ] chunks . ChunkDiskMapperRef {
if s . ooo == nil || s . ooo . oooHeadChunk == nil {
// There is no head chunk, so nothing to m-map here.
return 0
}
xor , _ := s . ooo . oooHeadChunk . chunk . ToXOR ( ) // Encode to XorChunk which is more compact and implements all of the needed functionality.
chunkRef := chunkDiskMapper . WriteChunk ( s . ref , s . ooo . oooHeadChunk . minTime , s . ooo . oooHeadChunk . maxTime , xor , true , handleChunkWriteError )
s . ooo . oooMmappedChunks = append ( s . ooo . oooMmappedChunks , & mmappedChunk {
ref : chunkRef ,
numSamples : uint16 ( xor . NumSamples ( ) ) ,
minTime : s . ooo . oooHeadChunk . minTime ,
maxTime : s . ooo . oooHeadChunk . maxTime ,
} )
// OOO is not enabled or there is no head chunk, so nothing to m-map here.
return nil
}
chks , err := s . ooo . oooHeadChunk . chunk . ToEncodedChunks ( math . MinInt64 , math . MaxInt64 )
if err != nil {
handleChunkWriteError ( err )
return nil
}
chunkRefs := make ( [ ] chunks . ChunkDiskMapperRef , 0 , 1 )
for _ , memchunk := range chks {
chunkRef := chunkDiskMapper . WriteChunk ( s . ref , s . ooo . oooHeadChunk . minTime , s . ooo . oooHeadChunk . maxTime , memchunk . chunk , true , handleChunkWriteError )
chunkRefs = append ( chunkRefs , chunkRef )
s . ooo . oooMmappedChunks = append ( s . ooo . oooMmappedChunks , & mmappedChunk {
ref : chunkRef ,
numSamples : uint16 ( memchunk . chunk . NumSamples ( ) ) ,
minTime : memchunk . minTime ,
maxTime : memchunk . maxTime ,
} )
}
s . ooo . oooHeadChunk = nil
return chunkRef
return chunkRefs
}
// mmapChunks will m-map all but first chunk on s.headChunks list.