...

Source file src/github.com/patrickmn/go-cache/cache.go

Documentation: github.com/patrickmn/go-cache

     1  package cache
     2  
     3  import (
     4  	"encoding/gob"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"runtime"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  type Item struct {
    14  	Object     interface{}
    15  	Expiration int64
    16  }
    17  
    18  // Returns true if the item has expired.
    19  func (item Item) Expired() bool {
    20  	if item.Expiration == 0 {
    21  		return false
    22  	}
    23  	return time.Now().UnixNano() > item.Expiration
    24  }
    25  
    26  const (
    27  	// For use with functions that take an expiration time.
    28  	NoExpiration time.Duration = -1
    29  	// For use with functions that take an expiration time. Equivalent to
    30  	// passing in the same expiration duration as was given to New() or
    31  	// NewFrom() when the cache was created (e.g. 5 minutes.)
    32  	DefaultExpiration time.Duration = 0
    33  )
    34  
    35  type Cache struct {
    36  	*cache
    37  	// If this is confusing, see the comment at the bottom of New()
    38  }
    39  
    40  type cache struct {
    41  	defaultExpiration time.Duration
    42  	items             map[string]Item
    43  	mu                sync.RWMutex
    44  	onEvicted         func(string, interface{})
    45  	janitor           *janitor
    46  }
    47  
    48  // Add an item to the cache, replacing any existing item. If the duration is 0
    49  // (DefaultExpiration), the cache's default expiration time is used. If it is -1
    50  // (NoExpiration), the item never expires.
    51  func (c *cache) Set(k string, x interface{}, d time.Duration) {
    52  	// "Inlining" of set
    53  	var e int64
    54  	if d == DefaultExpiration {
    55  		d = c.defaultExpiration
    56  	}
    57  	if d > 0 {
    58  		e = time.Now().Add(d).UnixNano()
    59  	}
    60  	c.mu.Lock()
    61  	c.items[k] = Item{
    62  		Object:     x,
    63  		Expiration: e,
    64  	}
    65  	// TODO: Calls to mu.Unlock are currently not deferred because defer
    66  	// adds ~200 ns (as of go1.)
    67  	c.mu.Unlock()
    68  }
    69  
    70  func (c *cache) set(k string, x interface{}, d time.Duration) {
    71  	var e int64
    72  	if d == DefaultExpiration {
    73  		d = c.defaultExpiration
    74  	}
    75  	if d > 0 {
    76  		e = time.Now().Add(d).UnixNano()
    77  	}
    78  	c.items[k] = Item{
    79  		Object:     x,
    80  		Expiration: e,
    81  	}
    82  }
    83  
    84  // Add an item to the cache, replacing any existing item, using the default
    85  // expiration.
    86  func (c *cache) SetDefault(k string, x interface{}) {
    87  	c.Set(k, x, DefaultExpiration)
    88  }
    89  
    90  // Add an item to the cache only if an item doesn't already exist for the given
    91  // key, or if the existing item has expired. Returns an error otherwise.
    92  func (c *cache) Add(k string, x interface{}, d time.Duration) error {
    93  	c.mu.Lock()
    94  	_, found := c.get(k)
    95  	if found {
    96  		c.mu.Unlock()
    97  		return fmt.Errorf("Item %s already exists", k)
    98  	}
    99  	c.set(k, x, d)
   100  	c.mu.Unlock()
   101  	return nil
   102  }
   103  
   104  // Set a new value for the cache key only if it already exists, and the existing
   105  // item hasn't expired. Returns an error otherwise.
   106  func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
   107  	c.mu.Lock()
   108  	_, found := c.get(k)
   109  	if !found {
   110  		c.mu.Unlock()
   111  		return fmt.Errorf("Item %s doesn't exist", k)
   112  	}
   113  	c.set(k, x, d)
   114  	c.mu.Unlock()
   115  	return nil
   116  }
   117  
   118  // Get an item from the cache. Returns the item or nil, and a bool indicating
   119  // whether the key was found.
   120  func (c *cache) Get(k string) (interface{}, bool) {
   121  	c.mu.RLock()
   122  	// "Inlining" of get and Expired
   123  	item, found := c.items[k]
   124  	if !found {
   125  		c.mu.RUnlock()
   126  		return nil, false
   127  	}
   128  	if item.Expiration > 0 {
   129  		if time.Now().UnixNano() > item.Expiration {
   130  			c.mu.RUnlock()
   131  			return nil, false
   132  		}
   133  	}
   134  	c.mu.RUnlock()
   135  	return item.Object, true
   136  }
   137  
   138  // GetWithExpiration returns an item and its expiration time from the cache.
   139  // It returns the item or nil, the expiration time if one is set (if the item
   140  // never expires a zero value for time.Time is returned), and a bool indicating
   141  // whether the key was found.
   142  func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {
   143  	c.mu.RLock()
   144  	// "Inlining" of get and Expired
   145  	item, found := c.items[k]
   146  	if !found {
   147  		c.mu.RUnlock()
   148  		return nil, time.Time{}, false
   149  	}
   150  
   151  	if item.Expiration > 0 {
   152  		if time.Now().UnixNano() > item.Expiration {
   153  			c.mu.RUnlock()
   154  			return nil, time.Time{}, false
   155  		}
   156  
   157  		// Return the item and the expiration time
   158  		c.mu.RUnlock()
   159  		return item.Object, time.Unix(0, item.Expiration), true
   160  	}
   161  
   162  	// If expiration <= 0 (i.e. no expiration time set) then return the item
   163  	// and a zeroed time.Time
   164  	c.mu.RUnlock()
   165  	return item.Object, time.Time{}, true
   166  }
   167  
   168  func (c *cache) get(k string) (interface{}, bool) {
   169  	item, found := c.items[k]
   170  	if !found {
   171  		return nil, false
   172  	}
   173  	// "Inlining" of Expired
   174  	if item.Expiration > 0 {
   175  		if time.Now().UnixNano() > item.Expiration {
   176  			return nil, false
   177  		}
   178  	}
   179  	return item.Object, true
   180  }
   181  
   182  // Increment an item of type int, int8, int16, int32, int64, uintptr, uint,
   183  // uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
   184  // item's value is not an integer, if it was not found, or if it is not
   185  // possible to increment it by n. To retrieve the incremented value, use one
   186  // of the specialized methods, e.g. IncrementInt64.
   187  func (c *cache) Increment(k string, n int64) error {
   188  	c.mu.Lock()
   189  	v, found := c.items[k]
   190  	if !found || v.Expired() {
   191  		c.mu.Unlock()
   192  		return fmt.Errorf("Item %s not found", k)
   193  	}
   194  	switch v.Object.(type) {
   195  	case int:
   196  		v.Object = v.Object.(int) + int(n)
   197  	case int8:
   198  		v.Object = v.Object.(int8) + int8(n)
   199  	case int16:
   200  		v.Object = v.Object.(int16) + int16(n)
   201  	case int32:
   202  		v.Object = v.Object.(int32) + int32(n)
   203  	case int64:
   204  		v.Object = v.Object.(int64) + n
   205  	case uint:
   206  		v.Object = v.Object.(uint) + uint(n)
   207  	case uintptr:
   208  		v.Object = v.Object.(uintptr) + uintptr(n)
   209  	case uint8:
   210  		v.Object = v.Object.(uint8) + uint8(n)
   211  	case uint16:
   212  		v.Object = v.Object.(uint16) + uint16(n)
   213  	case uint32:
   214  		v.Object = v.Object.(uint32) + uint32(n)
   215  	case uint64:
   216  		v.Object = v.Object.(uint64) + uint64(n)
   217  	case float32:
   218  		v.Object = v.Object.(float32) + float32(n)
   219  	case float64:
   220  		v.Object = v.Object.(float64) + float64(n)
   221  	default:
   222  		c.mu.Unlock()
   223  		return fmt.Errorf("The value for %s is not an integer", k)
   224  	}
   225  	c.items[k] = v
   226  	c.mu.Unlock()
   227  	return nil
   228  }
   229  
   230  // Increment an item of type float32 or float64 by n. Returns an error if the
   231  // item's value is not floating point, if it was not found, or if it is not
   232  // possible to increment it by n. Pass a negative number to decrement the
   233  // value. To retrieve the incremented value, use one of the specialized methods,
   234  // e.g. IncrementFloat64.
   235  func (c *cache) IncrementFloat(k string, n float64) error {
   236  	c.mu.Lock()
   237  	v, found := c.items[k]
   238  	if !found || v.Expired() {
   239  		c.mu.Unlock()
   240  		return fmt.Errorf("Item %s not found", k)
   241  	}
   242  	switch v.Object.(type) {
   243  	case float32:
   244  		v.Object = v.Object.(float32) + float32(n)
   245  	case float64:
   246  		v.Object = v.Object.(float64) + n
   247  	default:
   248  		c.mu.Unlock()
   249  		return fmt.Errorf("The value for %s does not have type float32 or float64", k)
   250  	}
   251  	c.items[k] = v
   252  	c.mu.Unlock()
   253  	return nil
   254  }
   255  
   256  // Increment an item of type int by n. Returns an error if the item's value is
   257  // not an int, or if it was not found. If there is no error, the incremented
   258  // value is returned.
   259  func (c *cache) IncrementInt(k string, n int) (int, error) {
   260  	c.mu.Lock()
   261  	v, found := c.items[k]
   262  	if !found || v.Expired() {
   263  		c.mu.Unlock()
   264  		return 0, fmt.Errorf("Item %s not found", k)
   265  	}
   266  	rv, ok := v.Object.(int)
   267  	if !ok {
   268  		c.mu.Unlock()
   269  		return 0, fmt.Errorf("The value for %s is not an int", k)
   270  	}
   271  	nv := rv + n
   272  	v.Object = nv
   273  	c.items[k] = v
   274  	c.mu.Unlock()
   275  	return nv, nil
   276  }
   277  
   278  // Increment an item of type int8 by n. Returns an error if the item's value is
   279  // not an int8, or if it was not found. If there is no error, the incremented
   280  // value is returned.
   281  func (c *cache) IncrementInt8(k string, n int8) (int8, error) {
   282  	c.mu.Lock()
   283  	v, found := c.items[k]
   284  	if !found || v.Expired() {
   285  		c.mu.Unlock()
   286  		return 0, fmt.Errorf("Item %s not found", k)
   287  	}
   288  	rv, ok := v.Object.(int8)
   289  	if !ok {
   290  		c.mu.Unlock()
   291  		return 0, fmt.Errorf("The value for %s is not an int8", k)
   292  	}
   293  	nv := rv + n
   294  	v.Object = nv
   295  	c.items[k] = v
   296  	c.mu.Unlock()
   297  	return nv, nil
   298  }
   299  
   300  // Increment an item of type int16 by n. Returns an error if the item's value is
   301  // not an int16, or if it was not found. If there is no error, the incremented
   302  // value is returned.
   303  func (c *cache) IncrementInt16(k string, n int16) (int16, error) {
   304  	c.mu.Lock()
   305  	v, found := c.items[k]
   306  	if !found || v.Expired() {
   307  		c.mu.Unlock()
   308  		return 0, fmt.Errorf("Item %s not found", k)
   309  	}
   310  	rv, ok := v.Object.(int16)
   311  	if !ok {
   312  		c.mu.Unlock()
   313  		return 0, fmt.Errorf("The value for %s is not an int16", k)
   314  	}
   315  	nv := rv + n
   316  	v.Object = nv
   317  	c.items[k] = v
   318  	c.mu.Unlock()
   319  	return nv, nil
   320  }
   321  
   322  // Increment an item of type int32 by n. Returns an error if the item's value is
   323  // not an int32, or if it was not found. If there is no error, the incremented
   324  // value is returned.
   325  func (c *cache) IncrementInt32(k string, n int32) (int32, error) {
   326  	c.mu.Lock()
   327  	v, found := c.items[k]
   328  	if !found || v.Expired() {
   329  		c.mu.Unlock()
   330  		return 0, fmt.Errorf("Item %s not found", k)
   331  	}
   332  	rv, ok := v.Object.(int32)
   333  	if !ok {
   334  		c.mu.Unlock()
   335  		return 0, fmt.Errorf("The value for %s is not an int32", k)
   336  	}
   337  	nv := rv + n
   338  	v.Object = nv
   339  	c.items[k] = v
   340  	c.mu.Unlock()
   341  	return nv, nil
   342  }
   343  
   344  // Increment an item of type int64 by n. Returns an error if the item's value is
   345  // not an int64, or if it was not found. If there is no error, the incremented
   346  // value is returned.
   347  func (c *cache) IncrementInt64(k string, n int64) (int64, error) {
   348  	c.mu.Lock()
   349  	v, found := c.items[k]
   350  	if !found || v.Expired() {
   351  		c.mu.Unlock()
   352  		return 0, fmt.Errorf("Item %s not found", k)
   353  	}
   354  	rv, ok := v.Object.(int64)
   355  	if !ok {
   356  		c.mu.Unlock()
   357  		return 0, fmt.Errorf("The value for %s is not an int64", k)
   358  	}
   359  	nv := rv + n
   360  	v.Object = nv
   361  	c.items[k] = v
   362  	c.mu.Unlock()
   363  	return nv, nil
   364  }
   365  
   366  // Increment an item of type uint by n. Returns an error if the item's value is
   367  // not an uint, or if it was not found. If there is no error, the incremented
   368  // value is returned.
   369  func (c *cache) IncrementUint(k string, n uint) (uint, error) {
   370  	c.mu.Lock()
   371  	v, found := c.items[k]
   372  	if !found || v.Expired() {
   373  		c.mu.Unlock()
   374  		return 0, fmt.Errorf("Item %s not found", k)
   375  	}
   376  	rv, ok := v.Object.(uint)
   377  	if !ok {
   378  		c.mu.Unlock()
   379  		return 0, fmt.Errorf("The value for %s is not an uint", k)
   380  	}
   381  	nv := rv + n
   382  	v.Object = nv
   383  	c.items[k] = v
   384  	c.mu.Unlock()
   385  	return nv, nil
   386  }
   387  
   388  // Increment an item of type uintptr by n. Returns an error if the item's value
   389  // is not an uintptr, or if it was not found. If there is no error, the
   390  // incremented value is returned.
   391  func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) {
   392  	c.mu.Lock()
   393  	v, found := c.items[k]
   394  	if !found || v.Expired() {
   395  		c.mu.Unlock()
   396  		return 0, fmt.Errorf("Item %s not found", k)
   397  	}
   398  	rv, ok := v.Object.(uintptr)
   399  	if !ok {
   400  		c.mu.Unlock()
   401  		return 0, fmt.Errorf("The value for %s is not an uintptr", k)
   402  	}
   403  	nv := rv + n
   404  	v.Object = nv
   405  	c.items[k] = v
   406  	c.mu.Unlock()
   407  	return nv, nil
   408  }
   409  
   410  // Increment an item of type uint8 by n. Returns an error if the item's value
   411  // is not an uint8, or if it was not found. If there is no error, the
   412  // incremented value is returned.
   413  func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) {
   414  	c.mu.Lock()
   415  	v, found := c.items[k]
   416  	if !found || v.Expired() {
   417  		c.mu.Unlock()
   418  		return 0, fmt.Errorf("Item %s not found", k)
   419  	}
   420  	rv, ok := v.Object.(uint8)
   421  	if !ok {
   422  		c.mu.Unlock()
   423  		return 0, fmt.Errorf("The value for %s is not an uint8", k)
   424  	}
   425  	nv := rv + n
   426  	v.Object = nv
   427  	c.items[k] = v
   428  	c.mu.Unlock()
   429  	return nv, nil
   430  }
   431  
   432  // Increment an item of type uint16 by n. Returns an error if the item's value
   433  // is not an uint16, or if it was not found. If there is no error, the
   434  // incremented value is returned.
   435  func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) {
   436  	c.mu.Lock()
   437  	v, found := c.items[k]
   438  	if !found || v.Expired() {
   439  		c.mu.Unlock()
   440  		return 0, fmt.Errorf("Item %s not found", k)
   441  	}
   442  	rv, ok := v.Object.(uint16)
   443  	if !ok {
   444  		c.mu.Unlock()
   445  		return 0, fmt.Errorf("The value for %s is not an uint16", k)
   446  	}
   447  	nv := rv + n
   448  	v.Object = nv
   449  	c.items[k] = v
   450  	c.mu.Unlock()
   451  	return nv, nil
   452  }
   453  
   454  // Increment an item of type uint32 by n. Returns an error if the item's value
   455  // is not an uint32, or if it was not found. If there is no error, the
   456  // incremented value is returned.
   457  func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) {
   458  	c.mu.Lock()
   459  	v, found := c.items[k]
   460  	if !found || v.Expired() {
   461  		c.mu.Unlock()
   462  		return 0, fmt.Errorf("Item %s not found", k)
   463  	}
   464  	rv, ok := v.Object.(uint32)
   465  	if !ok {
   466  		c.mu.Unlock()
   467  		return 0, fmt.Errorf("The value for %s is not an uint32", k)
   468  	}
   469  	nv := rv + n
   470  	v.Object = nv
   471  	c.items[k] = v
   472  	c.mu.Unlock()
   473  	return nv, nil
   474  }
   475  
   476  // Increment an item of type uint64 by n. Returns an error if the item's value
   477  // is not an uint64, or if it was not found. If there is no error, the
   478  // incremented value is returned.
   479  func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) {
   480  	c.mu.Lock()
   481  	v, found := c.items[k]
   482  	if !found || v.Expired() {
   483  		c.mu.Unlock()
   484  		return 0, fmt.Errorf("Item %s not found", k)
   485  	}
   486  	rv, ok := v.Object.(uint64)
   487  	if !ok {
   488  		c.mu.Unlock()
   489  		return 0, fmt.Errorf("The value for %s is not an uint64", k)
   490  	}
   491  	nv := rv + n
   492  	v.Object = nv
   493  	c.items[k] = v
   494  	c.mu.Unlock()
   495  	return nv, nil
   496  }
   497  
   498  // Increment an item of type float32 by n. Returns an error if the item's value
   499  // is not an float32, or if it was not found. If there is no error, the
   500  // incremented value is returned.
   501  func (c *cache) IncrementFloat32(k string, n float32) (float32, error) {
   502  	c.mu.Lock()
   503  	v, found := c.items[k]
   504  	if !found || v.Expired() {
   505  		c.mu.Unlock()
   506  		return 0, fmt.Errorf("Item %s not found", k)
   507  	}
   508  	rv, ok := v.Object.(float32)
   509  	if !ok {
   510  		c.mu.Unlock()
   511  		return 0, fmt.Errorf("The value for %s is not an float32", k)
   512  	}
   513  	nv := rv + n
   514  	v.Object = nv
   515  	c.items[k] = v
   516  	c.mu.Unlock()
   517  	return nv, nil
   518  }
   519  
   520  // Increment an item of type float64 by n. Returns an error if the item's value
   521  // is not an float64, or if it was not found. If there is no error, the
   522  // incremented value is returned.
   523  func (c *cache) IncrementFloat64(k string, n float64) (float64, error) {
   524  	c.mu.Lock()
   525  	v, found := c.items[k]
   526  	if !found || v.Expired() {
   527  		c.mu.Unlock()
   528  		return 0, fmt.Errorf("Item %s not found", k)
   529  	}
   530  	rv, ok := v.Object.(float64)
   531  	if !ok {
   532  		c.mu.Unlock()
   533  		return 0, fmt.Errorf("The value for %s is not an float64", k)
   534  	}
   535  	nv := rv + n
   536  	v.Object = nv
   537  	c.items[k] = v
   538  	c.mu.Unlock()
   539  	return nv, nil
   540  }
   541  
   542  // Decrement an item of type int, int8, int16, int32, int64, uintptr, uint,
   543  // uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
   544  // item's value is not an integer, if it was not found, or if it is not
   545  // possible to decrement it by n. To retrieve the decremented value, use one
   546  // of the specialized methods, e.g. DecrementInt64.
   547  func (c *cache) Decrement(k string, n int64) error {
   548  	// TODO: Implement Increment and Decrement more cleanly.
   549  	// (Cannot do Increment(k, n*-1) for uints.)
   550  	c.mu.Lock()
   551  	v, found := c.items[k]
   552  	if !found || v.Expired() {
   553  		c.mu.Unlock()
   554  		return fmt.Errorf("Item not found")
   555  	}
   556  	switch v.Object.(type) {
   557  	case int:
   558  		v.Object = v.Object.(int) - int(n)
   559  	case int8:
   560  		v.Object = v.Object.(int8) - int8(n)
   561  	case int16:
   562  		v.Object = v.Object.(int16) - int16(n)
   563  	case int32:
   564  		v.Object = v.Object.(int32) - int32(n)
   565  	case int64:
   566  		v.Object = v.Object.(int64) - n
   567  	case uint:
   568  		v.Object = v.Object.(uint) - uint(n)
   569  	case uintptr:
   570  		v.Object = v.Object.(uintptr) - uintptr(n)
   571  	case uint8:
   572  		v.Object = v.Object.(uint8) - uint8(n)
   573  	case uint16:
   574  		v.Object = v.Object.(uint16) - uint16(n)
   575  	case uint32:
   576  		v.Object = v.Object.(uint32) - uint32(n)
   577  	case uint64:
   578  		v.Object = v.Object.(uint64) - uint64(n)
   579  	case float32:
   580  		v.Object = v.Object.(float32) - float32(n)
   581  	case float64:
   582  		v.Object = v.Object.(float64) - float64(n)
   583  	default:
   584  		c.mu.Unlock()
   585  		return fmt.Errorf("The value for %s is not an integer", k)
   586  	}
   587  	c.items[k] = v
   588  	c.mu.Unlock()
   589  	return nil
   590  }
   591  
   592  // Decrement an item of type float32 or float64 by n. Returns an error if the
   593  // item's value is not floating point, if it was not found, or if it is not
   594  // possible to decrement it by n. Pass a negative number to decrement the
   595  // value. To retrieve the decremented value, use one of the specialized methods,
   596  // e.g. DecrementFloat64.
   597  func (c *cache) DecrementFloat(k string, n float64) error {
   598  	c.mu.Lock()
   599  	v, found := c.items[k]
   600  	if !found || v.Expired() {
   601  		c.mu.Unlock()
   602  		return fmt.Errorf("Item %s not found", k)
   603  	}
   604  	switch v.Object.(type) {
   605  	case float32:
   606  		v.Object = v.Object.(float32) - float32(n)
   607  	case float64:
   608  		v.Object = v.Object.(float64) - n
   609  	default:
   610  		c.mu.Unlock()
   611  		return fmt.Errorf("The value for %s does not have type float32 or float64", k)
   612  	}
   613  	c.items[k] = v
   614  	c.mu.Unlock()
   615  	return nil
   616  }
   617  
   618  // Decrement an item of type int by n. Returns an error if the item's value is
   619  // not an int, or if it was not found. If there is no error, the decremented
   620  // value is returned.
   621  func (c *cache) DecrementInt(k string, n int) (int, error) {
   622  	c.mu.Lock()
   623  	v, found := c.items[k]
   624  	if !found || v.Expired() {
   625  		c.mu.Unlock()
   626  		return 0, fmt.Errorf("Item %s not found", k)
   627  	}
   628  	rv, ok := v.Object.(int)
   629  	if !ok {
   630  		c.mu.Unlock()
   631  		return 0, fmt.Errorf("The value for %s is not an int", k)
   632  	}
   633  	nv := rv - n
   634  	v.Object = nv
   635  	c.items[k] = v
   636  	c.mu.Unlock()
   637  	return nv, nil
   638  }
   639  
   640  // Decrement an item of type int8 by n. Returns an error if the item's value is
   641  // not an int8, or if it was not found. If there is no error, the decremented
   642  // value is returned.
   643  func (c *cache) DecrementInt8(k string, n int8) (int8, error) {
   644  	c.mu.Lock()
   645  	v, found := c.items[k]
   646  	if !found || v.Expired() {
   647  		c.mu.Unlock()
   648  		return 0, fmt.Errorf("Item %s not found", k)
   649  	}
   650  	rv, ok := v.Object.(int8)
   651  	if !ok {
   652  		c.mu.Unlock()
   653  		return 0, fmt.Errorf("The value for %s is not an int8", k)
   654  	}
   655  	nv := rv - n
   656  	v.Object = nv
   657  	c.items[k] = v
   658  	c.mu.Unlock()
   659  	return nv, nil
   660  }
   661  
   662  // Decrement an item of type int16 by n. Returns an error if the item's value is
   663  // not an int16, or if it was not found. If there is no error, the decremented
   664  // value is returned.
   665  func (c *cache) DecrementInt16(k string, n int16) (int16, error) {
   666  	c.mu.Lock()
   667  	v, found := c.items[k]
   668  	if !found || v.Expired() {
   669  		c.mu.Unlock()
   670  		return 0, fmt.Errorf("Item %s not found", k)
   671  	}
   672  	rv, ok := v.Object.(int16)
   673  	if !ok {
   674  		c.mu.Unlock()
   675  		return 0, fmt.Errorf("The value for %s is not an int16", k)
   676  	}
   677  	nv := rv - n
   678  	v.Object = nv
   679  	c.items[k] = v
   680  	c.mu.Unlock()
   681  	return nv, nil
   682  }
   683  
   684  // Decrement an item of type int32 by n. Returns an error if the item's value is
   685  // not an int32, or if it was not found. If there is no error, the decremented
   686  // value is returned.
   687  func (c *cache) DecrementInt32(k string, n int32) (int32, error) {
   688  	c.mu.Lock()
   689  	v, found := c.items[k]
   690  	if !found || v.Expired() {
   691  		c.mu.Unlock()
   692  		return 0, fmt.Errorf("Item %s not found", k)
   693  	}
   694  	rv, ok := v.Object.(int32)
   695  	if !ok {
   696  		c.mu.Unlock()
   697  		return 0, fmt.Errorf("The value for %s is not an int32", k)
   698  	}
   699  	nv := rv - n
   700  	v.Object = nv
   701  	c.items[k] = v
   702  	c.mu.Unlock()
   703  	return nv, nil
   704  }
   705  
   706  // Decrement an item of type int64 by n. Returns an error if the item's value is
   707  // not an int64, or if it was not found. If there is no error, the decremented
   708  // value is returned.
   709  func (c *cache) DecrementInt64(k string, n int64) (int64, error) {
   710  	c.mu.Lock()
   711  	v, found := c.items[k]
   712  	if !found || v.Expired() {
   713  		c.mu.Unlock()
   714  		return 0, fmt.Errorf("Item %s not found", k)
   715  	}
   716  	rv, ok := v.Object.(int64)
   717  	if !ok {
   718  		c.mu.Unlock()
   719  		return 0, fmt.Errorf("The value for %s is not an int64", k)
   720  	}
   721  	nv := rv - n
   722  	v.Object = nv
   723  	c.items[k] = v
   724  	c.mu.Unlock()
   725  	return nv, nil
   726  }
   727  
   728  // Decrement an item of type uint by n. Returns an error if the item's value is
   729  // not an uint, or if it was not found. If there is no error, the decremented
   730  // value is returned.
   731  func (c *cache) DecrementUint(k string, n uint) (uint, error) {
   732  	c.mu.Lock()
   733  	v, found := c.items[k]
   734  	if !found || v.Expired() {
   735  		c.mu.Unlock()
   736  		return 0, fmt.Errorf("Item %s not found", k)
   737  	}
   738  	rv, ok := v.Object.(uint)
   739  	if !ok {
   740  		c.mu.Unlock()
   741  		return 0, fmt.Errorf("The value for %s is not an uint", k)
   742  	}
   743  	nv := rv - n
   744  	v.Object = nv
   745  	c.items[k] = v
   746  	c.mu.Unlock()
   747  	return nv, nil
   748  }
   749  
   750  // Decrement an item of type uintptr by n. Returns an error if the item's value
   751  // is not an uintptr, or if it was not found. If there is no error, the
   752  // decremented value is returned.
   753  func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) {
   754  	c.mu.Lock()
   755  	v, found := c.items[k]
   756  	if !found || v.Expired() {
   757  		c.mu.Unlock()
   758  		return 0, fmt.Errorf("Item %s not found", k)
   759  	}
   760  	rv, ok := v.Object.(uintptr)
   761  	if !ok {
   762  		c.mu.Unlock()
   763  		return 0, fmt.Errorf("The value for %s is not an uintptr", k)
   764  	}
   765  	nv := rv - n
   766  	v.Object = nv
   767  	c.items[k] = v
   768  	c.mu.Unlock()
   769  	return nv, nil
   770  }
   771  
   772  // Decrement an item of type uint8 by n. Returns an error if the item's value is
   773  // not an uint8, or if it was not found. If there is no error, the decremented
   774  // value is returned.
   775  func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) {
   776  	c.mu.Lock()
   777  	v, found := c.items[k]
   778  	if !found || v.Expired() {
   779  		c.mu.Unlock()
   780  		return 0, fmt.Errorf("Item %s not found", k)
   781  	}
   782  	rv, ok := v.Object.(uint8)
   783  	if !ok {
   784  		c.mu.Unlock()
   785  		return 0, fmt.Errorf("The value for %s is not an uint8", k)
   786  	}
   787  	nv := rv - n
   788  	v.Object = nv
   789  	c.items[k] = v
   790  	c.mu.Unlock()
   791  	return nv, nil
   792  }
   793  
   794  // Decrement an item of type uint16 by n. Returns an error if the item's value
   795  // is not an uint16, or if it was not found. If there is no error, the
   796  // decremented value is returned.
   797  func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) {
   798  	c.mu.Lock()
   799  	v, found := c.items[k]
   800  	if !found || v.Expired() {
   801  		c.mu.Unlock()
   802  		return 0, fmt.Errorf("Item %s not found", k)
   803  	}
   804  	rv, ok := v.Object.(uint16)
   805  	if !ok {
   806  		c.mu.Unlock()
   807  		return 0, fmt.Errorf("The value for %s is not an uint16", k)
   808  	}
   809  	nv := rv - n
   810  	v.Object = nv
   811  	c.items[k] = v
   812  	c.mu.Unlock()
   813  	return nv, nil
   814  }
   815  
   816  // Decrement an item of type uint32 by n. Returns an error if the item's value
   817  // is not an uint32, or if it was not found. If there is no error, the
   818  // decremented value is returned.
   819  func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) {
   820  	c.mu.Lock()
   821  	v, found := c.items[k]
   822  	if !found || v.Expired() {
   823  		c.mu.Unlock()
   824  		return 0, fmt.Errorf("Item %s not found", k)
   825  	}
   826  	rv, ok := v.Object.(uint32)
   827  	if !ok {
   828  		c.mu.Unlock()
   829  		return 0, fmt.Errorf("The value for %s is not an uint32", k)
   830  	}
   831  	nv := rv - n
   832  	v.Object = nv
   833  	c.items[k] = v
   834  	c.mu.Unlock()
   835  	return nv, nil
   836  }
   837  
   838  // Decrement an item of type uint64 by n. Returns an error if the item's value
   839  // is not an uint64, or if it was not found. If there is no error, the
   840  // decremented value is returned.
   841  func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) {
   842  	c.mu.Lock()
   843  	v, found := c.items[k]
   844  	if !found || v.Expired() {
   845  		c.mu.Unlock()
   846  		return 0, fmt.Errorf("Item %s not found", k)
   847  	}
   848  	rv, ok := v.Object.(uint64)
   849  	if !ok {
   850  		c.mu.Unlock()
   851  		return 0, fmt.Errorf("The value for %s is not an uint64", k)
   852  	}
   853  	nv := rv - n
   854  	v.Object = nv
   855  	c.items[k] = v
   856  	c.mu.Unlock()
   857  	return nv, nil
   858  }
   859  
   860  // Decrement an item of type float32 by n. Returns an error if the item's value
   861  // is not an float32, or if it was not found. If there is no error, the
   862  // decremented value is returned.
   863  func (c *cache) DecrementFloat32(k string, n float32) (float32, error) {
   864  	c.mu.Lock()
   865  	v, found := c.items[k]
   866  	if !found || v.Expired() {
   867  		c.mu.Unlock()
   868  		return 0, fmt.Errorf("Item %s not found", k)
   869  	}
   870  	rv, ok := v.Object.(float32)
   871  	if !ok {
   872  		c.mu.Unlock()
   873  		return 0, fmt.Errorf("The value for %s is not an float32", k)
   874  	}
   875  	nv := rv - n
   876  	v.Object = nv
   877  	c.items[k] = v
   878  	c.mu.Unlock()
   879  	return nv, nil
   880  }
   881  
   882  // Decrement an item of type float64 by n. Returns an error if the item's value
   883  // is not an float64, or if it was not found. If there is no error, the
   884  // decremented value is returned.
   885  func (c *cache) DecrementFloat64(k string, n float64) (float64, error) {
   886  	c.mu.Lock()
   887  	v, found := c.items[k]
   888  	if !found || v.Expired() {
   889  		c.mu.Unlock()
   890  		return 0, fmt.Errorf("Item %s not found", k)
   891  	}
   892  	rv, ok := v.Object.(float64)
   893  	if !ok {
   894  		c.mu.Unlock()
   895  		return 0, fmt.Errorf("The value for %s is not an float64", k)
   896  	}
   897  	nv := rv - n
   898  	v.Object = nv
   899  	c.items[k] = v
   900  	c.mu.Unlock()
   901  	return nv, nil
   902  }
   903  
   904  // Delete an item from the cache. Does nothing if the key is not in the cache.
   905  func (c *cache) Delete(k string) {
   906  	c.mu.Lock()
   907  	v, evicted := c.delete(k)
   908  	c.mu.Unlock()
   909  	if evicted {
   910  		c.onEvicted(k, v)
   911  	}
   912  }
   913  
   914  func (c *cache) delete(k string) (interface{}, bool) {
   915  	if c.onEvicted != nil {
   916  		if v, found := c.items[k]; found {
   917  			delete(c.items, k)
   918  			return v.Object, true
   919  		}
   920  	}
   921  	delete(c.items, k)
   922  	return nil, false
   923  }
   924  
   925  type keyAndValue struct {
   926  	key   string
   927  	value interface{}
   928  }
   929  
   930  // Delete all expired items from the cache.
   931  func (c *cache) DeleteExpired() {
   932  	var evictedItems []keyAndValue
   933  	now := time.Now().UnixNano()
   934  	c.mu.Lock()
   935  	for k, v := range c.items {
   936  		// "Inlining" of expired
   937  		if v.Expiration > 0 && now > v.Expiration {
   938  			ov, evicted := c.delete(k)
   939  			if evicted {
   940  				evictedItems = append(evictedItems, keyAndValue{k, ov})
   941  			}
   942  		}
   943  	}
   944  	c.mu.Unlock()
   945  	for _, v := range evictedItems {
   946  		c.onEvicted(v.key, v.value)
   947  	}
   948  }
   949  
   950  // Sets an (optional) function that is called with the key and value when an
   951  // item is evicted from the cache. (Including when it is deleted manually, but
   952  // not when it is overwritten.) Set to nil to disable.
   953  func (c *cache) OnEvicted(f func(string, interface{})) {
   954  	c.mu.Lock()
   955  	c.onEvicted = f
   956  	c.mu.Unlock()
   957  }
   958  
   959  // Write the cache's items (using Gob) to an io.Writer.
   960  //
   961  // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
   962  // documentation for NewFrom().)
   963  func (c *cache) Save(w io.Writer) (err error) {
   964  	enc := gob.NewEncoder(w)
   965  	defer func() {
   966  		if x := recover(); x != nil {
   967  			err = fmt.Errorf("Error registering item types with Gob library")
   968  		}
   969  	}()
   970  	c.mu.RLock()
   971  	defer c.mu.RUnlock()
   972  	for _, v := range c.items {
   973  		gob.Register(v.Object)
   974  	}
   975  	err = enc.Encode(&c.items)
   976  	return
   977  }
   978  
   979  // Save the cache's items to the given filename, creating the file if it
   980  // doesn't exist, and overwriting it if it does.
   981  //
   982  // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
   983  // documentation for NewFrom().)
   984  func (c *cache) SaveFile(fname string) error {
   985  	fp, err := os.Create(fname)
   986  	if err != nil {
   987  		return err
   988  	}
   989  	err = c.Save(fp)
   990  	if err != nil {
   991  		fp.Close()
   992  		return err
   993  	}
   994  	return fp.Close()
   995  }
   996  
   997  // Add (Gob-serialized) cache items from an io.Reader, excluding any items with
   998  // keys that already exist (and haven't expired) in the current cache.
   999  //
  1000  // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
  1001  // documentation for NewFrom().)
  1002  func (c *cache) Load(r io.Reader) error {
  1003  	dec := gob.NewDecoder(r)
  1004  	items := map[string]Item{}
  1005  	err := dec.Decode(&items)
  1006  	if err == nil {
  1007  		c.mu.Lock()
  1008  		defer c.mu.Unlock()
  1009  		for k, v := range items {
  1010  			ov, found := c.items[k]
  1011  			if !found || ov.Expired() {
  1012  				c.items[k] = v
  1013  			}
  1014  		}
  1015  	}
  1016  	return err
  1017  }
  1018  
  1019  // Load and add cache items from the given filename, excluding any items with
  1020  // keys that already exist in the current cache.
  1021  //
  1022  // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
  1023  // documentation for NewFrom().)
  1024  func (c *cache) LoadFile(fname string) error {
  1025  	fp, err := os.Open(fname)
  1026  	if err != nil {
  1027  		return err
  1028  	}
  1029  	err = c.Load(fp)
  1030  	if err != nil {
  1031  		fp.Close()
  1032  		return err
  1033  	}
  1034  	return fp.Close()
  1035  }
  1036  
  1037  // Copies all unexpired items in the cache into a new map and returns it.
  1038  func (c *cache) Items() map[string]Item {
  1039  	c.mu.RLock()
  1040  	defer c.mu.RUnlock()
  1041  	m := make(map[string]Item, len(c.items))
  1042  	now := time.Now().UnixNano()
  1043  	for k, v := range c.items {
  1044  		// "Inlining" of Expired
  1045  		if v.Expiration > 0 {
  1046  			if now > v.Expiration {
  1047  				continue
  1048  			}
  1049  		}
  1050  		m[k] = v
  1051  	}
  1052  	return m
  1053  }
  1054  
  1055  // Returns the number of items in the cache. This may include items that have
  1056  // expired, but have not yet been cleaned up.
  1057  func (c *cache) ItemCount() int {
  1058  	c.mu.RLock()
  1059  	n := len(c.items)
  1060  	c.mu.RUnlock()
  1061  	return n
  1062  }
  1063  
  1064  // Delete all items from the cache.
  1065  func (c *cache) Flush() {
  1066  	c.mu.Lock()
  1067  	c.items = map[string]Item{}
  1068  	c.mu.Unlock()
  1069  }
  1070  
  1071  type janitor struct {
  1072  	Interval time.Duration
  1073  	stop     chan bool
  1074  }
  1075  
  1076  func (j *janitor) Run(c *cache) {
  1077  	ticker := time.NewTicker(j.Interval)
  1078  	for {
  1079  		select {
  1080  		case <-ticker.C:
  1081  			c.DeleteExpired()
  1082  		case <-j.stop:
  1083  			ticker.Stop()
  1084  			return
  1085  		}
  1086  	}
  1087  }
  1088  
  1089  func stopJanitor(c *Cache) {
  1090  	c.janitor.stop <- true
  1091  }
  1092  
  1093  func runJanitor(c *cache, ci time.Duration) {
  1094  	j := &janitor{
  1095  		Interval: ci,
  1096  		stop:     make(chan bool),
  1097  	}
  1098  	c.janitor = j
  1099  	go j.Run(c)
  1100  }
  1101  
  1102  func newCache(de time.Duration, m map[string]Item) *cache {
  1103  	if de == 0 {
  1104  		de = -1
  1105  	}
  1106  	c := &cache{
  1107  		defaultExpiration: de,
  1108  		items:             m,
  1109  	}
  1110  	return c
  1111  }
  1112  
  1113  func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
  1114  	c := newCache(de, m)
  1115  	// This trick ensures that the janitor goroutine (which--granted it
  1116  	// was enabled--is running DeleteExpired on c forever) does not keep
  1117  	// the returned C object from being garbage collected. When it is
  1118  	// garbage collected, the finalizer stops the janitor goroutine, after
  1119  	// which c can be collected.
  1120  	C := &Cache{c}
  1121  	if ci > 0 {
  1122  		runJanitor(c, ci)
  1123  		runtime.SetFinalizer(C, stopJanitor)
  1124  	}
  1125  	return C
  1126  }
  1127  
  1128  // Return a new cache with a given default expiration duration and cleanup
  1129  // interval. If the expiration duration is less than one (or NoExpiration),
  1130  // the items in the cache never expire (by default), and must be deleted
  1131  // manually. If the cleanup interval is less than one, expired items are not
  1132  // deleted from the cache before calling c.DeleteExpired().
  1133  func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
  1134  	items := make(map[string]Item)
  1135  	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
  1136  }
  1137  
  1138  // Return a new cache with a given default expiration duration and cleanup
  1139  // interval. If the expiration duration is less than one (or NoExpiration),
  1140  // the items in the cache never expire (by default), and must be deleted
  1141  // manually. If the cleanup interval is less than one, expired items are not
  1142  // deleted from the cache before calling c.DeleteExpired().
  1143  //
  1144  // NewFrom() also accepts an items map which will serve as the underlying map
  1145  // for the cache. This is useful for starting from a deserialized cache
  1146  // (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g.
  1147  // make(map[string]Item, 500) to improve startup performance when the cache
  1148  // is expected to reach a certain minimum size.
  1149  //
  1150  // Only the cache's methods synchronize access to this map, so it is not
  1151  // recommended to keep any references to the map around after creating a cache.
  1152  // If need be, the map can be accessed at a later point using c.Items() (subject
  1153  // to the same caveat.)
  1154  //
  1155  // Note regarding serialization: When using e.g. gob, make sure to
  1156  // gob.Register() the individual types stored in the cache before encoding a
  1157  // map retrieved with c.Items(), and to register those same types before
  1158  // decoding a blob containing an items map.
  1159  func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache {
  1160  	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
  1161  }
  1162  

View as plain text