1161 lines · 30.3 KB · Go
RawDownload
package cache import (	"encoding/gob"	"fmt"	"io"	"os"	"runtime"	"sync"	"time") type Item struct {	Object     interface{}	Expiration int64} // Returns true if the item has expired.func (item Item) Expired() bool {	if item.Expiration == 0 {		return false	}	return time.Now().UnixNano() > item.Expiration} const (	// For use with functions that take an expiration time.	NoExpiration time.Duration = -1	// For use with functions that take an expiration time. Equivalent to	// passing in the same expiration duration as was given to New() or	// NewFrom() when the cache was created (e.g. 5 minutes.)	DefaultExpiration time.Duration = 0) type Cache struct {	*cache	// If this is confusing, see the comment at the bottom of New()} type cache struct {	defaultExpiration time.Duration	items             map[string]Item	mu                sync.RWMutex	onEvicted         func(string, interface{})	janitor           *janitor} // Add an item to the cache, replacing any existing item. If the duration is 0// (DefaultExpiration), the cache's default expiration time is used. If it is -1// (NoExpiration), the item never expires.func (c *cache) Set(k string, x interface{}, d time.Duration) {	// "Inlining" of set	var e int64	if d == DefaultExpiration {		d = c.defaultExpiration	}	if d > 0 {		e = time.Now().Add(d).UnixNano()	}	c.mu.Lock()	c.items[k] = Item{		Object:     x,		Expiration: e,	}	// TODO: Calls to mu.Unlock are currently not deferred because defer	// adds ~200 ns (as of go1.)	c.mu.Unlock()} func (c *cache) set(k string, x interface{}, d time.Duration) {	var e int64	if d == DefaultExpiration {		d = c.defaultExpiration	}	if d > 0 {		e = time.Now().Add(d).UnixNano()	}	c.items[k] = Item{		Object:     x,		Expiration: e,	}} // Add an item to the cache, replacing any existing item, using the default// expiration.func (c *cache) SetDefault(k string, x interface{}) {	c.Set(k, x, DefaultExpiration)} // Add an item to the cache only if an item doesn't already exist for the given// key, or if the existing item has expired. Returns an error otherwise.func (c *cache) Add(k string, x interface{}, d time.Duration) error {	c.mu.Lock()	_, found := c.get(k)	if found {		c.mu.Unlock()		return fmt.Errorf("Item %s already exists", k)	}	c.set(k, x, d)	c.mu.Unlock()	return nil} // Set a new value for the cache key only if it already exists, and the existing// item hasn't expired. Returns an error otherwise.func (c *cache) Replace(k string, x interface{}, d time.Duration) error {	c.mu.Lock()	_, found := c.get(k)	if !found {		c.mu.Unlock()		return fmt.Errorf("Item %s doesn't exist", k)	}	c.set(k, x, d)	c.mu.Unlock()	return nil} // Get an item from the cache. Returns the item or nil, and a bool indicating// whether the key was found.func (c *cache) Get(k string) (interface{}, bool) {	c.mu.RLock()	// "Inlining" of get and Expired	item, found := c.items[k]	if !found {		c.mu.RUnlock()		return nil, false	}	if item.Expiration > 0 {		if time.Now().UnixNano() > item.Expiration {			c.mu.RUnlock()			return nil, false		}	}	c.mu.RUnlock()	return item.Object, true} // GetWithExpiration returns an item and its expiration time from the cache.// It returns the item or nil, the expiration time if one is set (if the item// never expires a zero value for time.Time is returned), and a bool indicating// whether the key was found.func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {	c.mu.RLock()	// "Inlining" of get and Expired	item, found := c.items[k]	if !found {		c.mu.RUnlock()		return nil, time.Time{}, false	} 	if item.Expiration > 0 {		if time.Now().UnixNano() > item.Expiration {			c.mu.RUnlock()			return nil, time.Time{}, false		} 		// Return the item and the expiration time		c.mu.RUnlock()		return item.Object, time.Unix(0, item.Expiration), true	} 	// If expiration <= 0 (i.e. no expiration time set) then return the item	// and a zeroed time.Time	c.mu.RUnlock()	return item.Object, time.Time{}, true} func (c *cache) get(k string) (interface{}, bool) {	item, found := c.items[k]	if !found {		return nil, false	}	// "Inlining" of Expired	if item.Expiration > 0 {		if time.Now().UnixNano() > item.Expiration {			return nil, false		}	}	return item.Object, true} // Increment an item of type int, int8, int16, int32, int64, uintptr, uint,// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the// item's value is not an integer, if it was not found, or if it is not// possible to increment it by n. To retrieve the incremented value, use one// of the specialized methods, e.g. IncrementInt64.func (c *cache) Increment(k string, n int64) error {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return fmt.Errorf("Item %s not found", k)	}	switch v.Object.(type) {	case int:		v.Object = v.Object.(int) + int(n)	case int8:		v.Object = v.Object.(int8) + int8(n)	case int16:		v.Object = v.Object.(int16) + int16(n)	case int32:		v.Object = v.Object.(int32) + int32(n)	case int64:		v.Object = v.Object.(int64) + n	case uint:		v.Object = v.Object.(uint) + uint(n)	case uintptr:		v.Object = v.Object.(uintptr) + uintptr(n)	case uint8:		v.Object = v.Object.(uint8) + uint8(n)	case uint16:		v.Object = v.Object.(uint16) + uint16(n)	case uint32:		v.Object = v.Object.(uint32) + uint32(n)	case uint64:		v.Object = v.Object.(uint64) + uint64(n)	case float32:		v.Object = v.Object.(float32) + float32(n)	case float64:		v.Object = v.Object.(float64) + float64(n)	default:		c.mu.Unlock()		return fmt.Errorf("The value for %s is not an integer", k)	}	c.items[k] = v	c.mu.Unlock()	return nil} // Increment an item of type float32 or float64 by n. Returns an error if the// item's value is not floating point, if it was not found, or if it is not// possible to increment it by n. Pass a negative number to decrement the// value. To retrieve the incremented value, use one of the specialized methods,// e.g. IncrementFloat64.func (c *cache) IncrementFloat(k string, n float64) error {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return fmt.Errorf("Item %s not found", k)	}	switch v.Object.(type) {	case float32:		v.Object = v.Object.(float32) + float32(n)	case float64:		v.Object = v.Object.(float64) + n	default:		c.mu.Unlock()		return fmt.Errorf("The value for %s does not have type float32 or float64", k)	}	c.items[k] = v	c.mu.Unlock()	return nil} // Increment an item of type int by n. Returns an error if the item's value is// not an int, or if it was not found. If there is no error, the incremented// value is returned.func (c *cache) IncrementInt(k string, n int) (int, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(int)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an int", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type int8 by n. Returns an error if the item's value is// not an int8, or if it was not found. If there is no error, the incremented// value is returned.func (c *cache) IncrementInt8(k string, n int8) (int8, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(int8)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an int8", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type int16 by n. Returns an error if the item's value is// not an int16, or if it was not found. If there is no error, the incremented// value is returned.func (c *cache) IncrementInt16(k string, n int16) (int16, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(int16)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an int16", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type int32 by n. Returns an error if the item's value is// not an int32, or if it was not found. If there is no error, the incremented// value is returned.func (c *cache) IncrementInt32(k string, n int32) (int32, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(int32)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an int32", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type int64 by n. Returns an error if the item's value is// not an int64, or if it was not found. If there is no error, the incremented// value is returned.func (c *cache) IncrementInt64(k string, n int64) (int64, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(int64)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an int64", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type uint by n. Returns an error if the item's value is// not an uint, or if it was not found. If there is no error, the incremented// value is returned.func (c *cache) IncrementUint(k string, n uint) (uint, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(uint)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an uint", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type uintptr by n. Returns an error if the item's value// is not an uintptr, or if it was not found. If there is no error, the// incremented value is returned.func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(uintptr)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an uintptr", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type uint8 by n. Returns an error if the item's value// is not an uint8, or if it was not found. If there is no error, the// incremented value is returned.func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(uint8)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an uint8", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type uint16 by n. Returns an error if the item's value// is not an uint16, or if it was not found. If there is no error, the// incremented value is returned.func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(uint16)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an uint16", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type uint32 by n. Returns an error if the item's value// is not an uint32, or if it was not found. If there is no error, the// incremented value is returned.func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(uint32)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an uint32", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type uint64 by n. Returns an error if the item's value// is not an uint64, or if it was not found. If there is no error, the// incremented value is returned.func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) {	c.mu.Lock()	v, found := c.items[k]	if !found || v.Expired() {		c.mu.Unlock()		return 0, fmt.Errorf("Item %s not found", k)	}	rv, ok := v.Object.(uint64)	if !ok {		c.mu.Unlock()		return 0, fmt.Errorf("The value for %s is not an uint64", k)	}	nv := rv + n	v.Object = nv	c.items[k] = v	c.mu.Unlock()	return nv, nil} // Increment an item of type float32 by n. Returns an error if the item's value// is not an float32, or if it was not found. If there is no error, the// incremented value is returned.

Lines 1–500 of 1161.