ttlcache

package module
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2023 License: MIT Imports: 9 Imported by: 0

README

# TTLCache - an in-memory cache with item expiration

Go Reference Build Status Coverage Status Go Report Card

Features

  • Simple API.
  • Type parameters.
  • Item expiration and automatic deletion.
  • Automatic expiration time extension on each Get call.
  • Loader interface that is used to load/lazily initialize missing cache items.
  • Subscription to cache events (insertion and eviction).
  • Metrics.
  • Configurability.

Installation

go get github.com/jellydator/ttlcache/v3

Usage

The main type of ttlcache is Cache. It represents a single in-memory data store.

To create a new instance of ttlcache.Cache, the ttlcache.New() function should be called:

func main() {
	cache := ttlcache.New[string, string]()
}

Note that by default, a new cache instance does not let any of its items to expire or be automatically deleted. However, this feature can be activated by passing a few additional options into the ttlcache.New() function and calling the cache.Start() method:

func main() {
	cache := ttlcache.New[string, string](
		ttlcache.WithTTL[string, string](30 * time.Minute),
	)

	go cache.Start() // starts automatic expired item deletion
}

Even though the cache.Start() method handles expired item deletion well, there may be times when the system that uses ttlcache needs to determine when to delete the expired items itself. For example, it may need to delete them only when the resource load is at its lowest (e.g., after midnight, when the number of users/HTTP requests drops). So, in situations like these, instead of calling cache.Start(), the system could periodically call cache.DeleteExpired():

func main() {
	cache := ttlcache.New[string, string](
		ttlcache.WithTTL[string, string](30 * time.Minute),
	)

	for {
		time.Sleep(4 * time.Hour)
		cache.DeleteExpired()
	}
}

The data stored in ttlcache.Cache can be retrieved and updated with Set, Get, Delete, etc. methods:

func main() {
	cache := ttlcache.New[string, string](
		ttlcache.WithTTL[string, string](30 * time.Minute),
	)

	// insert data
	cache.Set("first", "value1", ttlcache.DefaultTTL)
	cache.Set("second", "value2", ttlcache.NoTTL)
	cache.Set("third", "value3", ttlcache.DefaultTTL)

	// retrieve data
	item := cache.Get("first")
	fmt.Println(item.Value(), item.ExpiresAt())

	// delete data
	cache.Delete("second")
	cache.DeleteExpired()
	cache.DeleteAll()
}

To subscribe to insertion and eviction events, cache.OnInsertion() and cache.OnEviction() methods should be used:

func main() {
	cache := ttlcache.New[string, string](
		ttlcache.WithTTL[string, string](30 * time.Minute),
		ttlcache.WithCapacity[string, string](300),
	)

	cache.OnInsertion(func(ctx context.Context, item *ttlcache.Item[string, string]) {
		fmt.Println(item.Value(), item.ExpiresAt())
	})
	cache.OnEviction(func(ctx context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, string]) {
		if reason == ttlcache.EvictionReasonCapacityReached {
			fmt.Println(item.Key(), item.Value())
		}
	})

	cache.Set("first", "value1", ttlcache.DefaultTTL)
	cache.DeleteAll()
}

To load data when the cache does not have it, a custom or existing implementation of ttlcache.Loader can be used:

func main() {
	loader := ttlcache.LoaderFunc[string, string](
		func(c *ttlcache.Cache[string, string], key string) *ttlcache.Item[string, string] {
			// load from file/make an HTTP request
			item := c.Set("key from file", "value from file")
			return item
		},
	)
	cache := ttlcache.New[string, string](
		ttlcache.WithLoader[string, string](loader),
	)

	item := cache.Get("key from file")
}

Documentation

Index

Constants

View Source
const (
	// NoTTL indicates that an item should never expire.
	NoTTL time.Duration = -1

	// DefaultTTL indicates that the default TTL
	// value should be used.
	DefaultTTL time.Duration = 0
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Cache

type Cache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Cache is a synchronised map of items that are automatically removed when they expire or the capacity is reached.

func New

func New[K comparable, V any](opts ...Option[K, V]) *Cache[K, V]

New creates a new instance of cache.

func (*Cache[K, V]) Delete

func (c *Cache[K, V]) Delete(key K)

Delete deletes an item from the cache. If the item associated with the key is not found, the method is no-op.

func (*Cache[K, V]) DeleteAll

func (c *Cache[K, V]) DeleteAll()

DeleteAll deletes all items from the cache.

func (*Cache[K, V]) DeleteExpired

func (c *Cache[K, V]) DeleteExpired()

DeleteExpired deletes all expired items from the cache.

func (*Cache[K, V]) Get

func (c *Cache[K, V]) Get(key K, opts ...Option[K, V]) *Item[K, V]

Get retrieves an item from the cache by the provided key. Unless this is disabled, it also extends/touches an item's expiration timestamp on successful retrieval. If the item is not found, a nil value is returned.

func (*Cache[K, V]) Items

func (c *Cache[K, V]) Items() map[K]*Item[K, V]

Items returns a copy of all items in the cache. It does not update any expiration timestamps.

func (*Cache[K, V]) Keys

func (c *Cache[K, V]) Keys() []K

Keys returns all keys currently present in the cache.

func (*Cache[K, V]) Len

func (c *Cache[K, V]) Len() int

Len returns the number of items in the cache.

func (*Cache[K, V]) Metrics

func (c *Cache[K, V]) Metrics() Metrics

Metrics returns the metrics of the cache.

func (*Cache[K, V]) OnEviction

func (c *Cache[K, V]) OnEviction(fn func(context.Context, EvictionReason, *Item[K, V])) func()

OnEviction adds the provided function to be executed when an item is evicted/deleted from the cache. The function is executed on a separate goroutine and does not block the flow of the cache manager. The returned function may be called to delete the subscription function from the list of eviction subscribers. When the returned function is called, it blocks until all instances of the same subscription function return. A context is used to notify the subscription function when the returned/deletion function is called.

func (*Cache[K, V]) OnInsertion

func (c *Cache[K, V]) OnInsertion(fn func(context.Context, *Item[K, V])) func()

OnInsertion adds the provided function to be executed when a new item is inserted into the cache. The function is executed on a separate goroutine and does not block the flow of the cache manager. The returned function may be called to delete the subscription function from the list of insertion subscribers. When the returned function is called, it blocks until all instances of the same subscription function return. A context is used to notify the subscription function when the returned/deletion function is called.

func (*Cache[K, V]) Set

func (c *Cache[K, V]) Set(key K, value V, ttl time.Duration) *Item[K, V]

Set creates a new item from the provided key and value, adds it to the cache and then returns it. If an item associated with the provided key already exists, the new item overwrites the existing one.

func (*Cache[K, V]) Start

func (c *Cache[K, V]) Start()

Start starts an automatic cleanup process that periodically deletes expired items. It blocks until Stop is called.

func (*Cache[K, V]) Stop

func (c *Cache[K, V]) Stop()

Stop stops the automatic cleanup process. It blocks until the cleanup process exits.

func (*Cache[K, V]) Touch

func (c *Cache[K, V]) Touch(key K)

Touch simulates an item's retrieval without actually returning it. Its main purpose is to extend an item's expiration timestamp. If the item is not found, the method is no-op.

type EvictionReason

type EvictionReason int

EvictionReason is used to specify why a certain item was evicted/deleted.

const (
	EvictionReasonDeleted EvictionReason = iota + 1
	EvictionReasonCapacityReached
	EvictionReasonExpired
)

Available eviction reasons.

type Item

type Item[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Item holds all the information that is associated with a single cache value.

func (*Item[K, V]) ExpiresAt

func (item *Item[K, V]) ExpiresAt() time.Time

ExpiresAt returns the expiration timestamp of the item.

func (*Item[K, V]) IsExpired

func (item *Item[K, V]) IsExpired() bool

IsExpired returns a bool value that indicates whether the item is expired.

func (*Item[K, V]) Key

func (item *Item[K, V]) Key() K

Key returns the key of the item.

func (*Item[K, V]) TTL

func (item *Item[K, V]) TTL() time.Duration

TTL returns the TTL value of the item.

func (*Item[K, V]) Value

func (item *Item[K, V]) Value() V

Value returns the value of the item.

type Loader

type Loader[K comparable, V any] interface {
	// Load should execute a custom item retrieval logic and
	// return the item that is associated with the key.
	// It should return nil if the item is not found/valid.
	// The method is allowed to fetch data from the cache instance
	// or update it for future use.
	Load(c *Cache[K, V], key K) *Item[K, V]
}

Loader is an interface that handles missing data loading.

type LoaderFunc

type LoaderFunc[K comparable, V any] func(*Cache[K, V], K) *Item[K, V]

LoaderFunc type is an adapter that allows the use of ordinary functions as data loaders.

func (LoaderFunc[K, V]) Load

func (l LoaderFunc[K, V]) Load(c *Cache[K, V], key K) *Item[K, V]

Load executes a custom item retrieval logic and returns the item that is associated with the key. It returns nil if the item is not found/valid.

type Metrics

type Metrics struct {
	// Insertions specifies how many items were inserted.
	Insertions uint64

	// Hits specifies how many items were successfully retrieved
	// from the cache.
	// Retrievals made with a loader function are not tracked.
	Hits uint64

	// Misses specifies how many items were not found in the cache.
	// Retrievals made with a loader function are tracked as well.
	Misses uint64

	// Evictions specifies how many items were removed from the
	// cache.
	Evictions uint64
}

Metrics contains common cache metrics calculated over the course of the cache's lifetime.

type Option

type Option[K comparable, V any] interface {
	// contains filtered or unexported methods
}

Option sets a specific cache option.

func WithCapacity

func WithCapacity[K comparable, V any](c uint64) Option[K, V]

WithCapacity sets the maximum capacity of the cache. It has no effect when passing into Get().

func WithDisableTouchOnHit

func WithDisableTouchOnHit[K comparable, V any]() Option[K, V]

WithDisableTouchOnHit prevents the cache instance from extending/touching an item's expiration timestamp when it is being retrieved. When passing into Get(), it overrides the default value of the cache.

func WithLoader

func WithLoader[K comparable, V any](l Loader[K, V]) Option[K, V]

WithLoader sets the loader of the cache. When passing into Get(), it sets an epheral loader that is used instead of the cache's default one.

func WithMetrics added in v1.0.2

func WithMetrics[K comparable, V any](appName, cacheName string) Option[K, V]

func WithRelevanceTTL

func WithRelevanceTTL[K comparable, V any](ttl time.Duration) Option[K, V]

WithRelevanceTTL sets the relevance TTL of the cache. If relevanceTTL is expired, cache async reload value from Loader

func WithTTL

func WithTTL[K comparable, V any](ttl time.Duration) Option[K, V]

WithTTL sets the TTL of the cache. It has no effect when passing into Get().

type SuppressedLoader

type SuppressedLoader[K comparable, V any] struct {
	// contains filtered or unexported fields
}

SuppressedLoader wraps another Loader and suppresses duplicate calls to its Load method.

func NewSuppressedLoader

func NewSuppressedLoader[K comparable, V any](loader Loader[K, V], group *singleflight.Group) *SuppressedLoader[K, V]

NewSuppressedLoader creates a new instance of suppressed loader. If the group parameter is nil, a newly created instance of *singleflight.Group is used.

func (*SuppressedLoader[K, V]) Load

func (l *SuppressedLoader[K, V]) Load(c *Cache[K, V], key K) *Item[K, V]

Load executes a custom item retrieval logic and returns the item that is associated with the key. It returns nil if the item is not found/valid. It also ensures that only one execution of the wrapped Loader's Load method is in-flight for a given key at a time.

Jump to

Keyboard shortcuts

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