Merge pull request #2559 from prometheus/beorn7/storage

storage: Replace fpIter by sortedFPs
This commit is contained in:
Björn Rabenstein 2017-04-03 16:56:21 +02:00 committed by GitHub
commit 1c6240fc40
2 changed files with 33 additions and 39 deletions

View file

@ -106,26 +106,18 @@ func (sm *seriesMap) iter() <-chan fingerprintSeriesPair {
return ch return ch
} }
// fpIter returns a channel that produces all fingerprints in the seriesMap. The // sortedFPs returns a sorted slice of all the fingerprints in the seriesMap.
// channel will be closed once all fingerprints have been received. Not func (sm *seriesMap) sortedFPs() model.Fingerprints {
// consuming all fingerprints from the channel will leak a goroutine. The
// semantics of concurrent modification of seriesMap is the similar as the one
// for iterating over a map with a 'range' clause. However, if the next element
// in iteration order is removed after the current element has been received
// from the channel, it will still be produced by the channel.
func (sm *seriesMap) fpIter() <-chan model.Fingerprint {
ch := make(chan model.Fingerprint)
go func() {
sm.mtx.RLock() sm.mtx.RLock()
fps := make(model.Fingerprints, 0, len(sm.m))
for fp := range sm.m { for fp := range sm.m {
sm.mtx.RUnlock() fps = append(fps, fp)
ch <- fp
sm.mtx.RLock()
} }
sm.mtx.RUnlock() sm.mtx.RUnlock()
close(ch)
}() // Sorting could take some time, so do it outside of the lock.
return ch sort.Sort(fps)
return fps
} }
type memorySeries struct { type memorySeries struct {

View file

@ -18,6 +18,7 @@ import (
"container/list" "container/list"
"errors" "errors"
"fmt" "fmt"
"math/rand"
"runtime" "runtime"
"sort" "sort"
"sync" "sync"
@ -419,13 +420,11 @@ func (s *MemorySeriesStorage) Start() (err error) {
log.Info("Loading series map and head chunks...") log.Info("Loading series map and head chunks...")
s.fpToSeries, s.numChunksToPersist, err = p.loadSeriesMapAndHeads() s.fpToSeries, s.numChunksToPersist, err = p.loadSeriesMapAndHeads()
for fp := range s.fpToSeries.fpIter() { for _, series := range s.fpToSeries.m {
if series, ok := s.fpToSeries.get(fp); ok {
if !series.headChunkClosed { if !series.headChunkClosed {
s.headChunks.Inc() s.headChunks.Inc()
} }
} }
}
if err != nil { if err != nil {
return err return err
@ -1330,16 +1329,8 @@ func (s *MemorySeriesStorage) waitForNextFP(numberOfFPs int, maxWaitDurationFact
func (s *MemorySeriesStorage) cycleThroughMemoryFingerprints() chan model.Fingerprint { func (s *MemorySeriesStorage) cycleThroughMemoryFingerprints() chan model.Fingerprint {
memoryFingerprints := make(chan model.Fingerprint) memoryFingerprints := make(chan model.Fingerprint)
go func() { go func() {
var fpIter <-chan model.Fingerprint defer close(memoryFingerprints)
firstPass := true
defer func() {
if fpIter != nil {
for range fpIter {
// Consume the iterator.
}
}
close(memoryFingerprints)
}()
for { for {
// Initial wait, also important if there are no FPs yet. // Initial wait, also important if there are no FPs yet.
@ -1347,9 +1338,15 @@ func (s *MemorySeriesStorage) cycleThroughMemoryFingerprints() chan model.Finger
return return
} }
begin := time.Now() begin := time.Now()
fpIter = s.fpToSeries.fpIter() fps := s.fpToSeries.sortedFPs()
if firstPass {
// Start first pass at a random location in the
// key space to cover the whole key space even
// in the case of frequent restarts.
fps = fps[rand.Intn(len(fps)):]
}
count := 0 count := 0
for fp := range fpIter { for _, fp := range fps {
select { select {
case memoryFingerprints <- fp: case memoryFingerprints <- fp:
case <-s.loopStopping: case <-s.loopStopping:
@ -1364,11 +1361,16 @@ func (s *MemorySeriesStorage) cycleThroughMemoryFingerprints() chan model.Finger
count++ count++
} }
if count > 0 { if count > 0 {
msg := "full"
if firstPass {
msg = "initial partial"
}
log.Infof( log.Infof(
"Completed maintenance sweep through %d in-memory fingerprints in %v.", "Completed %s maintenance sweep through %d in-memory fingerprints in %v.",
count, time.Since(begin), msg, count, time.Since(begin),
) )
} }
firstPass = false
} }
}() }()