func (c *SizedLRU) Add(key Key, value lruItem) (ok bool) {
	roundedUpSizeOnDisk := roundUp4k(value.sizeOnDisk)
	if roundedUpSizeOnDisk > c.maxSize {
		return false
	}
	var sizeDelta, uncompressedSizeDelta int64
	if ee, ok := c.cache[key]; ok {
		sizeDelta = roundedUpSizeOnDisk - roundUp4k(ee.Value.(*entry).value.sizeOnDisk)
		if c.reservedSize+sizeDelta > c.maxSize {
			return false
		}
		uncompressedSizeDelta = roundUp4k(value.size) - roundUp4k(ee.Value.(*entry).value.size)
		c.ll.MoveToFront(ee)
		c.counterOverwrittenBytes.Add(float64(ee.Value.(*entry).value.sizeOnDisk))
		prevValue := ee.Value.(*entry).value
		if c.onEvict != nil {
			c.onEvict(key, prevValue)
		}
		ee.Value.(*entry).value = value
	} else {
		sizeDelta = roundedUpSizeOnDisk
		if c.reservedSize+sizeDelta > c.maxSize {
			return false
		}
		uncompressedSizeDelta = roundUp4k(value.size)
		ele := c.ll.PushFront(&entry{key, value})
		c.cache[key] = ele
	}
	for c.currentSize+sizeDelta > c.maxSize {
		ele := c.ll.Back()
		if ele != nil {
			c.removeElement(ele)
		}
	}
	c.currentSize += sizeDelta
	c.uncompressedSize += uncompressedSizeDelta
	c.gaugeCacheSizeBytes.Set(float64(c.currentSize))
	c.gaugeCacheLogicalBytes.Set(float64(c.uncompressedSize))
	return true
}
Add adds a (key, value) to the cache, evicting items as necessary.
Add returns false and does not add the item if the item size is
larger than the maximum size of the cache, or if the item cannot
be added to the cache because too much space is reserved.

Note that this function rounds file sizes up to the nearest
BlockSize (4096) bytes, as an estimate of actual disk usage since
most linux filesystems default to 4kb blocks.
package disk
import (
	"container/list"
	"errors"
	"fmt"
	"github.com/prometheus/client_golang/prometheus"
)
type Key interface{}
type EvictCallback func(key Key, value lruItem)
type SizedLRU struct {
	ll *list.List
	cache map[interface{}]*list.Element
	currentSize int64
	uncompressedSize int64
	reservedSize int64
	maxSize int64
	onEvict EvictCallback
	gaugeCacheSizeBytes     prometheus.Gauge
	gaugeCacheLogicalBytes  prometheus.Gauge
	counterEvictedBytes     prometheus.Counter
	counterOverwrittenBytes prometheus.Counter
}
type entry struct {
	key   Key
	value lruItem
}
const BlockSize = 4096
func NewSizedLRU(maxSize int64, onEvict EvictCallback) SizedLRU {
	return SizedLRU{
		maxSize: maxSize,
		ll:      list.New(),
		cache:   make(map[interface{}]*list.Element),
		onEvict: onEvict,
		gaugeCacheSizeBytes: prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "bazel_remote_disk_cache_size_bytes",
			Help: "The current number of bytes in the disk backend",
		}),
		gaugeCacheLogicalBytes: prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "bazel_remote_disk_cache_logical_bytes",
			Help: "The current number of bytes in the disk backend if they were uncompressed",
		}),
		counterEvictedBytes: prometheus.NewCounter(prometheus.CounterOpts{
			Name: "bazel_remote_disk_cache_evicted_bytes_total",
			Help: "The total number of bytes evicted from disk backend, due to full cache",
		}),
		counterOverwrittenBytes: prometheus.NewCounter(prometheus.CounterOpts{
			Name: "bazel_remote_disk_cache_overwritten_bytes_total",
			Help: "The total number of bytes removed from disk backend, due to put of already existing key",
		}),
	}
}
func (c *SizedLRU) RegisterMetrics() {
	prometheus.MustRegister(c.gaugeCacheSizeBytes)
	prometheus.MustRegister(c.gaugeCacheLogicalBytes)
	prometheus.MustRegister(c.counterEvictedBytes)
	prometheus.MustRegister(c.counterOverwrittenBytes)
}