func (c *Cache) Add(bucketName []byte, key []byte, value []byte) bool {
	if !c.enable {
		return false
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	var bucket map[string]*list.Element
	var ok bool
	bucketKey := string(bucketName)
	if bucket, ok = c.items[bucketKey]; !ok {
		bucket = make(map[string]*list.Element)
		c.logger.Printf("cache new bucket %s", bucketKey)
	}
	dst := make([]byte, len(value))
	copy(dst, value)
	if ent, ok := bucket[string(key)]; ok {
		c.evictList.MoveToFront(ent)
		ent.Value.(*entry).value = dst
		return false
	}
	ent := &entry{bucketName, key, dst}
	entry := c.evictList.PushFront(ent)
	bucket[string(key)] = entry
	c.items[bucketKey] = bucket
	c.size += uint64(ent.Size())
	c.count++
	atomic.AddInt64(&c.stats.AddCount, 1)
	evict := c.maxSize > 0 && c.size > c.maxSize
	if evict {
		c.removeOldest()
	}
	return evict
}
Add adds a value to the cache.  Returns true if an eviction occurred.
package store
import (
	"container/list"
	"sync"
	"sync/atomic"
	"github.com/lodastack/store/log"
	"github.com/lodastack/store/model"
)
type EvictCallback func(bucket []byte, key []byte, value []byte)
type Cache struct {
	mu        sync.RWMutex
	count     int
	evictList *list.List
	items     map[string]map[string]*list.Element
	onEvict   EvictCallback
	size    uint64
	maxSize uint64
	enable bool
	stats  *CacheStatistics
	logger log.Logger
}
type entry struct {
	bucket []byte
	key    []byte
	value  []byte
}
func (e *entry) Size() int {
	return len(e.bucket) + len(e.key) + len(e.value)
}
const (
	statCacheMemoryBytes  = "memBytes"  
	statCachePurgeCount   = "purgeCount"
	statAddCount          = "addCount"
	statGetCount          = "getCount"
	statHitCount          = "hitCount"
	statMissCount         = "missCount"
	statRemoveCount       = "removeCount"
	statRemoveBucketCount = "removeBucketCount"
	statRemoveOldestCount = "removeOldestCount"
	statKeysCount         = "keysCount"
)
type CacheStatistics struct {
	MemSizeBytes      int64
	PurgeCount        int64
	AddCount          int64
	GetCount          int64
	HitCount          int64
	MissCount         int64
	RemoveCount       int64
	RemoveBucketCount int64
	RemoveOldestCount int64
	KeysCount         int64
}
func NewCache(maxSize uint64, onEvict EvictCallback, logger log.Logger) *Cache {
	c := &Cache{
		count:     0,
		maxSize:   maxSize,
		items:     make(map[string]map[string]*list.Element),
		evictList: list.New(),
		onEvict:   onEvict,
		stats:     &CacheStatistics{},
		logger:    logger,
	}
	return c
}
func (c *Cache) Open() {
	c.enable = true
	if c.logger == nil {
		c.logger = log.New()
	}
}
func (c *Cache) Statistics(tags map[string]string) []model.Statistic {
	return []model.Statistic{{
		Name: "store_cache",
		Tags: tags,
		Values: map[string]interface{}{
			statCacheMemoryBytes:  c.size,
			statCachePurgeCount:   atomic.LoadInt64(&c.stats.PurgeCount),
			statAddCount:          atomic.LoadInt64(&c.stats.AddCount),
			statHitCount:          atomic.LoadInt64(&c.stats.HitCount),
			statMissCount:         atomic.LoadInt64(&c.stats.MissCount),
			statGetCount:          atomic.LoadInt64(&c.stats.GetCount),
			statRemoveCount:       atomic.LoadInt64(&c.stats.RemoveCount),
			statRemoveBucketCount: atomic.LoadInt64(&c.stats.RemoveBucketCount),
			statRemoveOldestCount: atomic.LoadInt64(&c.stats.RemoveOldestCount),
			statKeysCount:         c.Len(),
		},
	}}
}
func (c *Cache) Purge() {
	if !c.enable {
		return
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	c.items = make(map[string]map[string]*list.Element)
	c.count = 0
	c.size = 0
	c.evictList.Init()
	atomic.AddInt64(&c.stats.PurgeCount, 1)
}