Documentation ¶
Overview ¶
Package cache offers a time aware least-recently-used cache implementation
Cache implements an least recently used cache with optional capacity and time-to-use. The empty value is usable as a cache that never expires and has no limit on the number of entries.
Initialization ¶
For example, the following code will work:
c := &cache.Cache{} c.Add("hello", "world") if v, ok := c.Get("hello"); ok { log.Println(v) }
However, a more useful cache would have a set capacity and/or a TTU so that it won't grow forever. The initialization function can be used along with functional parameters to configure a more useful Cache:
c := cache.New(cache.WithTTU(30 * time.Second), cache.WithCapacity(100))
The above will limit the cache to a maximum number of 100 entries and the entries are considered expired if not access within 30s.
Also note that since TTU is optional, one can create an LRU cache (not time aware) by omitting the time-to-use:
c := cache.New(cache.WithCapacity(1000))
Purging ¶
When using a TTU, the cache needs to be purged periodically of expired entries. The Purge() method will remove any expired entries before returning. It is recommended that you run Purge() periodically to avoid accummulating expired entries. You can do that in a goroutine like the naive example below:
c := cache.New(cache.WithTTU(30 * time.Minute)) ctx, cancel = context.WithCancel(ctx) defer cancel() go func() { for { select { case <-time.After(1 * time.Minute): c.Purge() case <-ctx.Done(): return } } }()
There is also a helper function that uses a time.Tick to run it at a given frequency:
c := cache.New(cache.WithTTU(30 * time.Minute)) stop := c.StartPurger(1 * time.Minute) defer stop()
Index ¶
- type Byter
- type Cache
- func (c *Cache) Add(key, val interface{})
- func (c *Cache) Cap() int
- func (c *Cache) Get(key interface{}) (value interface{}, ok bool)
- func (c *Cache) Len() int
- func (c *Cache) Purge() int
- func (c *Cache) Remove(key interface{}) interface{}
- func (c *Cache) StartPurger(freq time.Duration) (stop func())
- func (c *Cache) TTU() time.Duration
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Byter ¶
type Byter interface {
Bytes() []byte
}
Byter is implemented by any valie that has a Bytes method, which should returns a byte representation of the value. The Bytes method is used by to identify the correct shard of a given key.
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache implements a simple LRU-cache with optional time-to-use. The empty value is a cache with no max number of entries and no TTU. It is safe for concurrent use
func New ¶
New creates a new cache with the provided max number of entries and ttl.
Example ¶
package main import ( "fmt" "time" "github.com/rselbach/cache" ) func main() { // create a new cache with a time-to-use of half a second c := cache.New(cache.WithTTU(500 * time.Millisecond)) // add something to the cache c.Add("hello", "world") // tries to retrieve the value from the key v, ok := c.Get("hello") fmt.Println("v", v, "ok", ok) // sleep so the item expires time.Sleep(1 * time.Second) c.Purge() // purges cache of old items // tries to retrieve the value again v, ok = c.Get("hello") fmt.Println("v", v, "ok", ok) }
Output: v world ok true v <nil> ok false
func (*Cache) Add ¶
func (c *Cache) Add(key, val interface{})
Add adds the new keyval pair to the cache. If the key is already present, it is updated
func (*Cache) Get ¶
Get retrieves an element from the cache. It also returns a second value indicating whether the key was found
func (*Cache) Remove ¶
func (c *Cache) Remove(key interface{}) interface{}
Remove removes an entry from the cache from its key. It returns the cached value or nil if not present.
func (*Cache) StartPurger ¶
StartPurger is a helper function that starts a goroutine to periodically call Purge() at the provided freq. The returned stop function must be called to stop the purger, otherwise the garbage collector will not be able to free it and it will "leak".
Also, the freq can have a detrimental effect on performance as the purger must lock the entire cache while it purges the cache. Since the Cache will ignore expired items, the need for frequent purges is greatly reduced.
Example ¶
package main import ( "fmt" "time" "github.com/rselbach/cache" ) func main() { // create a cache with a half a 1-second TTU and maximum capacity of 100 // entries c := cache.New(cache.WithTTU(1*time.Second), cache.WithCapacity(100)) // start an aggressive purger that will run every second stop := c.StartPurger(1 * time.Second) defer stop() // add 200 several entries for i := 0; i < 200; i++ { c.Add(i, i) } // note that even though we added 200 entries, it will only hold the last // 100 due to the capacity limit fmt.Println("Len:", c.Len()) // wait for the purger to remove expired items (all of them as the // TTU was 1s) time.Sleep(3 * time.Second) // now Len() is 0 as all entries have expired and were automatically purged fmt.Println("Len:", c.Len()) }
Output: Len: 100 Len: 0
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option configures the Cache
func WithCapacity ¶
WithCapacity configures the max capacity of each shard. If cap is 0, then there is no set capacity and the cache will grow indefinely
func WithShards ¶
WithShards configures the number of shards to split the cache. This number must be larger than 0. By default, the cache uses a single shard.