cache

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 28, 2018 License: MIT Imports: 10 Imported by: 0

README

cache

cache is a time aware LRU cache.

I've been writing simplified, specialized versions of these caches for a lot of projects over the years, with a goroutine to periodically purge items, so I thought I'd just put together a more generalized version I can use.

Please see the documentation for more info.

Very much a work in progress.

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

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

func New(opts ...Option) *Cache

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) Cap

func (c *Cache) Cap() int

Cap returns the capacity of this cache

func (*Cache) Get

func (c *Cache) Get(key interface{}) (value interface{}, ok bool)

Get retrieves an element from the cache. It also returns a second value indicating whether the key was found

func (*Cache) Len

func (c *Cache) Len() int

Len returns the number of entries currently held in the cache

func (*Cache) Purge

func (c *Cache) Purge() int

Purge will remove entries that are expired

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

func (c *Cache) StartPurger(freq time.Duration) (stop func())

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

func (*Cache) TTU

func (c *Cache) TTU() time.Duration

TTU returns the time-to-use of the cache

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option configures the Cache

func WithCapacity

func WithCapacity(cap int) Option

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

func WithShards(n int32) Option

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.

func WithTTU

func WithTTU(ttu time.Duration) Option

WithTTU configures the cache to expire elements older than the provided time-to-use (TTU)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL