cache

package module
v0.0.0-...-df5b3c9 Latest Latest
Warning

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

Go to latest
Published: Dec 9, 2024 License: MIT Imports: 18 Imported by: 0

README

Cache library for Go

Go

Right now this project is under constraction.

This project was started as a fork of go-cache, but later I decided to rewrite it.

How to test

For launching all tests a redis instance required

WITH_REDIS="redis://localhost:6379" make test

or create file named .env.local with next content

WITH_REDIS=redis://localhost:6379

and run tests by

make test

If this redis instance is in production, tests should be pointed to another redis db on this instance, like

WITH_REDIS=redis://localhost:6379/1

In this case tests will use first and next redis databases (assuming db 0 contains production data). Tests use more databases, starting from db of connection.

Documentation

Overview

Example (AdvancedUsage)
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)

var obj Object
if err := mycache.Once(context.Background(), cache.Item{
	Key:   "mykey2",
	Value: &obj, // destination
	Do: func(ctx context.Context) (any, error) {
		return Object{Str: "mystring2", Num: 42}, nil
	},
}); err != nil {
	log.Fatal(err)
}

fmt.Println(obj)
Output:

{mystring2 42}
Example (BasicUsage)
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)

ctx := context.Background()
key := "mykey1"
obj := Object{Str: "mystring1", Num: 42}

item := cache.Item{Key: key, Value: &obj}
if err := mycache.Set(ctx, item); err != nil {
	log.Fatal(err)
}

var wanted Object
item.Value = &wanted
if missed, err := mycache.Get(ctx, item); err != nil {
	log.Fatal(err)
} else if len(missed) == 0 {
	fmt.Println(wanted)
} else {
	fmt.Println("not found")
}
Output:

{mystring1 42}

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrRedisCache = newRedisCacheError(errors.New("redis cache error"))

Functions

This section is empty.

Types

type Cache

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

func New

func New(opts ...Option) *Cache
Example
rdb := MustNewRedisCmdable()
mycache := cache.New(
	cache.WithLock(10*time.Second, 3*time.Second, func() cache.WaitLockIter {
		return cache.NewWaitLockIter(time.Second, 10*time.Second)
	})).
	WithDefaultTTL(24*time.Hour).
	WithStats(true).
	WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)

fmt.Println(mycache.ResolveKey("mykey3"))
Output:

expx-cache-v0:mykey3

func (*Cache) DefaultTTL

func (self *Cache) DefaultTTL() time.Duration

func (*Cache) Delete

func (self *Cache) Delete(ctx context.Context, keys ...string) error
Example
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)
if err := mycache.Delete(
	context.Background(), "mykey1", "mykey2", "mykey3", "mykey4", "mykey5",
); err != nil {
	log.Fatal(err)
}
Output:

func (*Cache) DeleteFromLocalCache

func (self *Cache) DeleteFromLocalCache(keys ...string)

func (*Cache) DeleteFromRedis

func (self *Cache) DeleteFromRedis(ctx context.Context, keys ...string) error

func (*Cache) Err

func (self *Cache) Err() error

func (*Cache) Exists

func (self *Cache) Exists(ctx context.Context, key string) (bool, error)

Exists reports whether value for the given key exists.

Example
rdb := MustNewRedisCmdable()
mycache := cache.New().WithTinyLFU(1000, time.Hour).WithRedis(rdb)

ok, err := mycache.Exists(context.Background(), "mykey1")
if err != nil {
	log.Fatal(err)
}
fmt.Println(ok)

mycache.WithNamespace("expx-cache-v0:")
ok, err = mycache.Exists(context.Background(), "mykey1")
if err != nil {
	log.Fatal(err)
}
fmt.Println(ok)
Output:

false
true

func (*Cache) Get

func (self *Cache) Get(ctx context.Context, items ...Item) ([]Item, error)
Example
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)

var value1, value2 Object
missed, err := mycache.Get(context.Background(),
	cache.Item{Key: "mykey1", Value: &value1},
	cache.Item{Key: "mykey2", Value: &value2},
	cache.Item{Key: "mykey3"},
)
if err != nil {
	log.Fatal(err)
}

fmt.Println("missed:", len(missed), missed[0].Key)
fmt.Println("value1:", value1)
fmt.Println("value2:", value2)
Output:

missed: 1 mykey3
value1: {mystring1 42}
value2: {mystring2 42}

func (*Cache) GetSet

func (self *Cache) GetSet(ctx context.Context, items ...Item) error
Example
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)

var value1, value2 Object
err := mycache.GetSet(context.Background(),
	cache.Item{
		Key:   "mykey1",
		Value: &value1,
		Do: func(ctx context.Context) (any, error) {
			return Object{Str: "mystring1", Num: 42}, nil
		},
	},
	cache.Item{
		Key:   "mykey5",
		Value: &value2,
		Do: func(ctx context.Context) (any, error) {
			return Object{Str: "mystring5", Num: 42}, nil
		},
	},
)
if err != nil {
	log.Fatal(err)
}

fmt.Println("value1:", value1)
fmt.Println("value2:", value2)
Output:

value1: {mystring1 42}
value2: {mystring5 42}

func (*Cache) Marshal

func (self *Cache) Marshal(value any) ([]byte, error)

func (*Cache) Namespace

func (self *Cache) Namespace() string

func (*Cache) New

func (self *Cache) New(opts ...Option) *Cache

func (*Cache) Once

func (self *Cache) Once(ctx context.Context, item Item) error

Once gets the item.Value for the given item.Key from the cache or executes, caches, and returns the results of the given item.Do, making sure that only one execution is in-flight for a given item.Key at a time. If a duplicate comes in, the duplicate caller waits for the original to complete and receives the same results.

func (*Cache) OnceLock

func (self *Cache) OnceLock(ctx context.Context, item Item) error
Example
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)

var obj Object
if err := mycache.OnceLock(context.Background(), cache.Item{
	Key:   "mykey1",
	Value: &obj, // destination
	Do: func(ctx context.Context) (any, error) {
		return Object{Str: "mystring6", Num: 42}, nil
	},
}); err != nil {
	log.Fatal(err)
}

fmt.Println(obj)
Output:

{mystring1 42}

func (*Cache) ResetErr

func (self *Cache) ResetErr() error

func (*Cache) ResolveKey

func (self *Cache) ResolveKey(key string) string

func (*Cache) ResolveKeyLock

func (self *Cache) ResolveKeyLock(key string) string

func (*Cache) Set

func (self *Cache) Set(ctx context.Context, items ...Item) error

Set caches the item.

Example
rdb := MustNewRedisCmdable()
mycache := cache.New().WithNamespace("expx-cache-v0:").
	WithTinyLFU(1000, time.Hour).WithRedis(rdb)
value1 := Object{Str: "mystring3", Num: 42}
value2 := Object{Str: "mystring4", Num: 42}
err := mycache.Set(context.Background(),
	cache.Item{Key: "mykey3", Value: &value1},
	cache.Item{Key: "mykey4", Value: &value2},
)
fmt.Println(err)
Output:

<nil>

func (*Cache) Stats

func (self *Cache) Stats() Stats

Stats returns cache statistics.

func (*Cache) Unmarshal

func (self *Cache) Unmarshal(b []byte, value any) error

func (*Cache) WithDefaultTTL

func (self *Cache) WithDefaultTTL(ttl time.Duration) *Cache

func (*Cache) WithItemMaxProcs

func (self *Cache) WithItemMaxProcs(n int) *Cache

func (*Cache) WithKeyWrapper

func (self *Cache) WithKeyWrapper(fn func(key string) string) *Cache

func (*Cache) WithLocalCache

func (self *Cache) WithLocalCache(client LocalCache) *Cache

func (*Cache) WithLocalStats

func (self *Cache) WithLocalStats(fn func(c *Cache) error, opts ...Option,
) (Stats, error)

func (*Cache) WithMarshal

func (self *Cache) WithMarshal(fn MarshalFunc) *Cache

func (*Cache) WithNamespace

func (self *Cache) WithNamespace(namespace string) *Cache

func (*Cache) WithPrefixLock

func (self *Cache) WithPrefixLock(s string) *Cache

func (*Cache) WithRedis

func (self *Cache) WithRedis(rdb redis.Cmdable) *Cache

func (*Cache) WithRedisCache

func (self *Cache) WithRedisCache(client RedisCache) *Cache

func (*Cache) WithRequestId

func (self *Cache) WithRequestId(id string) *Cache

func (*Cache) WithStats

func (self *Cache) WithStats(val bool) *Cache

func (*Cache) WithTinyLFU

func (self *Cache) WithTinyLFU(size int, ttl time.Duration) *Cache

func (*Cache) WithUnmarshal

func (self *Cache) WithUnmarshal(fn UnmarshalFunc) *Cache

func (*Cache) WrapKey

func (self *Cache) WrapKey(key string) string

type Item

type Item struct {
	Key   string
	Value any

	// TTL is the cache expiration time.
	// Default TTL configured using [WithDefaultTTL] and it's 1 hour by default.
	TTL time.Duration

	// Do returns value to be cached.
	Do func(ctx context.Context) (any, error)

	// SkipLocalCache skips local cache as if it is not set.
	SkipLocalCache bool
}

type LocalCache

type LocalCache interface {
	Set(key string, data []byte)
	Get(key string) []byte
	Del(key string)
}

type MarshalFunc

type MarshalFunc func(any) ([]byte, error)

type Option

type Option func(c *Cache)

func WithItemMaxProcs

func WithItemMaxProcs(n int) Option

func WithLock

func WithLock(ttl, tick time.Duration, iter func() WaitLockIter) Option

func WithLockNotFound

func WithLockNotFound(fn func(key, value string) error) Option

func WithMarshalMaxProcs

func WithMarshalMaxProcs(n int) Option

func WithNoErr

func WithNoErr() Option

type RedisCache

type RedisCache interface {
	Del(ctx context.Context, keys []string) error
	Get(ctx context.Context, maxItems int,
		keyIter func(itemIdx int) string) (func() ([]byte, bool), error)
	Set(ctx context.Context, maxItems int,
		iter func(itemIdx int) (key string, b []byte, ttl time.Duration)) error

	LockGet(ctx context.Context, keySet, value string, ttl time.Duration,
		keyGet string) (ok bool, b []byte, err error)
	Expire(ctx context.Context, key string, ttl time.Duration) (bool, error)
	Unlock(ctx context.Context, key, value string) (bool, error)
	Listen(ctx context.Context, key string, ready ...func() error) (string, error)
}

type RedisCacheError

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

func (*RedisCacheError) Is

func (self *RedisCacheError) Is(target error) bool

func (*RedisCacheError) Unwrap

func (self *RedisCacheError) Unwrap() error

type Stats

type Stats struct {
	Hits        uint64
	Misses      uint64
	LocalHits   uint64
	LocalMisses uint64
}

func (*Stats) Merge

func (self *Stats) Merge(s *Stats)

func (*Stats) Stats

func (self *Stats) Stats() Stats

type UnmarshalFunc

type UnmarshalFunc func([]byte, any) error

type WaitLockIter

type WaitLockIter func() time.Duration

func NewWaitLockIter

func NewWaitLockIter(start time.Duration, seq ...time.Duration) WaitLockIter

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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