github.com/sequix/cortex@v1.1.6/pkg/chunk/cache/background.go (about) 1 package cache 2 3 import ( 4 "context" 5 "flag" 6 "sync" 7 8 opentracing "github.com/opentracing/opentracing-go" 9 otlog "github.com/opentracing/opentracing-go/log" 10 "github.com/prometheus/client_golang/prometheus" 11 "github.com/prometheus/client_golang/prometheus/promauto" 12 ) 13 14 var ( 15 droppedWriteBack = promauto.NewCounterVec(prometheus.CounterOpts{ 16 Namespace: "cortex", 17 Name: "cache_dropped_background_writes_total", 18 Help: "Total count of dropped write backs to cache.", 19 }, []string{"name"}) 20 queueLength = promauto.NewGaugeVec(prometheus.GaugeOpts{ 21 Namespace: "cortex", 22 Name: "cache_background_queue_length", 23 Help: "Length of the cache background write queue.", 24 }, []string{"name"}) 25 ) 26 27 // BackgroundConfig is config for a Background Cache. 28 type BackgroundConfig struct { 29 WriteBackGoroutines int `yaml:"writeback_goroutines,omitempty"` 30 WriteBackBuffer int `yaml:"writeback_buffer,omitempty"` 31 } 32 33 // RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet 34 func (cfg *BackgroundConfig) RegisterFlagsWithPrefix(prefix string, description string, f *flag.FlagSet) { 35 f.IntVar(&cfg.WriteBackGoroutines, prefix+"memcache.write-back-goroutines", 10, description+"How many goroutines to use to write back to memcache.") 36 f.IntVar(&cfg.WriteBackBuffer, prefix+"memcache.write-back-buffer", 10000, description+"How many chunks to buffer for background write back.") 37 } 38 39 type backgroundCache struct { 40 Cache 41 42 wg sync.WaitGroup 43 quit chan struct{} 44 bgWrites chan backgroundWrite 45 name string 46 47 droppedWriteBack prometheus.Counter 48 queueLength prometheus.Gauge 49 } 50 51 type backgroundWrite struct { 52 keys []string 53 bufs [][]byte 54 } 55 56 // NewBackground returns a new Cache that does stores on background goroutines. 57 func NewBackground(name string, cfg BackgroundConfig, cache Cache) Cache { 58 c := &backgroundCache{ 59 Cache: cache, 60 quit: make(chan struct{}), 61 bgWrites: make(chan backgroundWrite, cfg.WriteBackBuffer), 62 name: name, 63 droppedWriteBack: droppedWriteBack.WithLabelValues(name), 64 queueLength: queueLength.WithLabelValues(name), 65 } 66 67 c.wg.Add(cfg.WriteBackGoroutines) 68 for i := 0; i < cfg.WriteBackGoroutines; i++ { 69 go c.writeBackLoop() 70 } 71 72 return c 73 } 74 75 // Stop the background flushing goroutines. 76 func (c *backgroundCache) Stop() error { 77 close(c.quit) 78 c.wg.Wait() 79 80 return c.Cache.Stop() 81 } 82 83 // Store writes keys for the cache in the background. 84 func (c *backgroundCache) Store(ctx context.Context, keys []string, bufs [][]byte) { 85 bgWrite := backgroundWrite{ 86 keys: keys, 87 bufs: bufs, 88 } 89 select { 90 case c.bgWrites <- bgWrite: 91 c.queueLength.Add(float64(len(keys))) 92 default: 93 c.droppedWriteBack.Add(float64(len(keys))) 94 sp := opentracing.SpanFromContext(ctx) 95 if sp != nil { 96 sp.LogFields(otlog.Int("dropped", len(keys))) 97 } 98 } 99 } 100 101 func (c *backgroundCache) writeBackLoop() { 102 defer c.wg.Done() 103 104 for { 105 select { 106 case bgWrite, ok := <-c.bgWrites: 107 if !ok { 108 return 109 } 110 c.queueLength.Sub(float64(len(bgWrite.keys))) 111 c.Cache.Store(context.Background(), bgWrite.keys, bgWrite.bufs) 112 113 case <-c.quit: 114 return 115 } 116 } 117 }