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  }