ttlcache

package module
v2.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2020 License: MIT Imports: 4 Imported by: 0

README

TTLCache - an in-memory cache with expiration

Documentation Release

TTLCache is a simple key/value cache in golang with the following functions:

  1. Expiration of items based on time, or custom function
  2. Loader function to retrieve missing keys can be provided. Additional Get calls on the same key block while fetching is in progress (groupcache style).
  3. Individual expiring time or global expiring time, you can choose
  4. Auto-Extending expiration on Get -or- DNS style TTL, see SkipTTLExtensionOnHit(bool)
  5. Can trigger callback on key expiration
  6. Cleanup resources by calling Close() at end of lifecycle.
  7. Thread-safe with comprehensive testing suite. This code is in production at bol.com on critical systems.

Note (issue #25): by default, due to historic reasons, the TTL will be reset on each cache hit and you need to explicitly configure the cache to use a TTL that will not get extended.

Build Status Go Report Card Coverage Status GitHub issues license

Usage

You can copy it as a full standalone demo program.

package main

import (
	"fmt"
	"time"

	"github.com/ReneKroon/ttlcache/v2"
)

var (
	notFound = ttlcache.ErrNotFound
	isClosed = ttlcache.ErrClosed
)

func main() {
	newItemCallback := func(key string, value interface{}) {
		fmt.Printf("New key(%s) added\n", key)
	}
	checkExpirationCallback := func(key string, value interface{}) bool {
		if key == "key1" {
			// if the key equals "key1", the value
			// will not be allowed to expire
			return false
		}
		// all other values are allowed to expire
		return true
	}
	expirationCallback := func(key string, value interface{}) {
		fmt.Printf("This key(%s) has expired\n", key)
	}

	loaderFunction := func(key string) (data interface{}, ttl time.Duration, err error) {
		ttl = time.Second * 300
		data, err = getFromNetwork(key)

		return data, ttl, err
	}

	cache := ttlcache.NewCache()
	defer cache.Close()
	cache.SetTTL(time.Duration(10 * time.Second))
	cache.SetExpirationCallback(expirationCallback)
	cache.SetLoaderFunction(loaderFunction)
	cache.SetNewItemCallback(newItemCallback)
	cache.SetCheckExpirationCallback(checkExpirationCallback)

	cache.Set("key", "value")
	cache.SetWithTTL("keyWithTTL", "value", 10*time.Second)

	if value, exists := cache.Get("key"); exists == nil {
		fmt.Printf("Got value: %v\n", value)
	}
	count := cache.Count()
	if result := cache.Remove("keyNNN"); result == notFound {
		fmt.Printf("Not found, %d items left\n", count)
	}
}

func getFromNetwork(key string) (string, error) {
	time.Sleep(time.Millisecond * 30)
	return "value", nil
}
TTLCache - Some design considerations
  1. The complexity of the current cache is already quite high. Therefore not all requests can be implemented in a straight-forward manner.
  2. The locking should be done only in the exported functions and startExpirationProcessing of the Cache struct. Else data races can occur or recursive locks are needed, which are both unwanted.
  3. I prefer correct functionality over fast tests. It's ok for new tests to take seconds to proof something.
Original Project

TTLCache was forked from wunderlist/ttlcache to add extra functions not avaiable in the original scope. The main differences are:

  1. A item can store any kind of object, previously, only strings could be saved
  2. Optionally, you can add callbacks too: check if a value should expire, be notified if a value expires, and be notified when new values are added to the cache
  3. The expiration can be either global or per item
  4. Items can exist without expiration time (time.Zero)
  5. Expirations and callbacks are realtime. Don't have a pooling time to check anymore, now it's done with a heap.
  6. A cache count limiter

Documentation

Index

Constants

View Source
const (
	// ItemNotExpire Will avoid the item being expired by TTL, but can still be exired by callback etc.
	ItemNotExpire time.Duration = -1
	// ItemExpireWithGlobalTTL will use the global TTL when set.
	ItemExpireWithGlobalTTL time.Duration = 0
)

Variables

View Source
var (
	// ErrClosed is raised when operating on a cache where Close() has already been called.
	ErrClosed = errors.New("cache already closed")
	// ErrNotFound indicates that the requested key is not present in the cache
	ErrNotFound = errors.New("key not found")
)

Functions

This section is empty.

Types

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache is a synchronized map of items that can auto-expire once stale

func NewCache

func NewCache() *Cache

NewCache is a helper to create instance of the Cache struct

func (*Cache) Close

func (cache *Cache) Close() error

Close calls Purge after stopping the goroutine that does ttl checking, for a clean shutdown. The cache is no longer cleaning up after the first call to Close, repeated calls are safe and return ErrClosed.

func (*Cache) Count

func (cache *Cache) Count() int

Count returns the number of items in the cache. Returns zero when the cache has been closed.

func (*Cache) Get

func (cache *Cache) Get(key string) (interface{}, error)

Get is a thread-safe way to lookup items Every lookup, also touches the item, hence extending it's life

func (*Cache) Purge

func (cache *Cache) Purge() error

Purge will remove all entries

func (*Cache) Remove

func (cache *Cache) Remove(key string) error

Remove removes an item from the cache if it exists, triggers expiration callback when set. Can return ErrNotFound if the entry was not present.

func (*Cache) Set

func (cache *Cache) Set(key string, data interface{}) error

Set is a thread-safe way to add new items to the map.

func (*Cache) SetCacheSizeLimit added in v2.1.0

func (cache *Cache) SetCacheSizeLimit(limit int)

SetCacheSizeLimit sets a limit to the amount of cached items. If a new item is getting cached, the closes item to being timed out will be replaced Set to 0 to turn off

func (*Cache) SetCheckExpirationCallback

func (cache *Cache) SetCheckExpirationCallback(callback CheckExpireCallback)

SetCheckExpirationCallback sets a callback that will be called when an item is about to expire in order to allow external code to decide whether the item expires or remains for another TTL cycle

func (*Cache) SetExpirationCallback

func (cache *Cache) SetExpirationCallback(callback ExpireCallback)

SetExpirationCallback sets a callback that will be called when an item expires

func (*Cache) SetLoaderFunction

func (cache *Cache) SetLoaderFunction(loader LoaderFunction)

SetLoaderFunction allows you to set a function to retrieve cache misses. The signature matches that of the Get function. Additional Get calls on the same key block while fetching is in progress (groupcache style).

func (*Cache) SetNewItemCallback

func (cache *Cache) SetNewItemCallback(callback ExpireCallback)

SetNewItemCallback sets a callback that will be called when a new item is added to the cache

func (*Cache) SetTTL

func (cache *Cache) SetTTL(ttl time.Duration) error

SetTTL sets the global TTL value for items in the cache, which can be overridden at the item level.

func (*Cache) SetWithTTL

func (cache *Cache) SetWithTTL(key string, data interface{}, ttl time.Duration) error

SetWithTTL is a thread-safe way to add new items to the map with individual ttl.

func (*Cache) SkipTTLExtensionOnHit

func (cache *Cache) SkipTTLExtensionOnHit(value bool)

SkipTTLExtensionOnHit allows the user to change the cache behaviour. When this flag is set to true it will no longer extend TTL of items when they are retrieved using Get, or when their expiration condition is evaluated using SetCheckExpirationCallback.

type CheckExpireCallback

type CheckExpireCallback func(key string, value interface{}) bool

CheckExpireCallback is used as a callback for an external check on item expiration

type ExpireCallback

type ExpireCallback func(key string, value interface{})

ExpireCallback is used as a callback on item expiration or when notifying of an item new to the cache

type LoaderFunction

type LoaderFunction func(key string) (data interface{}, ttl time.Duration, err error)

LoaderFunction can be supplied to retrieve an item where a cache miss occurs. Supply an item specific ttl or Duration.Zero

Jump to

Keyboard shortcuts

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