cachier

package module
v1.1.0 Latest Latest
Warning

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

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

README

Build Status GoDoc

Cachier

Cachier is a Go library that provides an interface for dealing with cache. There is a CacheEngine interface which requires you to implement common cache methods (like Get, Set, Delete, etc). When implemented, you wrap this CacheEngine into the Cache struct. This struct has some methods implemented like GetOrCompute method (shortcut for fetching a hit or computing/writing a miss).

There are also three implementations included:

  • LRUCache: a wrapper of hashicorp/golang-lru which fulfills the CacheEngine interface

  • RedisCache: CacheEngine based on redis

  • CacheWithSubcache: Implementation of combination of primary cache with fast L1 subcache. E.g. primary Redis cache and fast (and small) LRU subcache. But any other implementations of CacheEngine can be used.

Compression

Compression can be used with Redis Cache. There are three compression providers implemented:

  • Zstd (github.com/DataDog/zstd),
  • S2 (github.com/klauspost/compress/s2),
  • Lz4 (github.com/cloudflare/golz4).

Every provider has an unique identifier (ID). Provider id must be <= 255. It must be written in one byte

  • NoCompression - 0 - special provider for small input data (<= 1KB)
  • Zstd - 1
  • S2 - 2
  • Lz4 - 3

Input data which are smaller or equal 1KB are never compressed by default

The definition of functions NewRedisCache and NewRedisCacheWithLogger is extend and the last function argument is the pointer to compression.Engine. If the *compression.Engine == nil data are not compressed.

The compression engine uses compresison providers to compress and decompress data. Data are always compressed with the default provider but can be decompressed by multiple providers. Based on the footer added to compressed data the engine selects the right provider to decompress data

In order to start using compression add *compression.Engine to the redis cache constructor

engine, err := compression.NewEngine(providerID,compressionParameters)
NewRedisCache(
	redisClient 
	keyPrefix,
	marshal,
	unmarshal,
	ttl,
	engine,

Where compression.NewEngine(providerID byte, compressionParameters map[string]interface{}) creates *compression.Engine where

  • default compression engine is selected based on providerID
  • supported compression providers: zstd, lz4, s2
  • input <= 1 KB is not compressed
  • compressionParameters map contains compression parameters which are used to configure the engine and providers. Two parameters are currently supported:
    • level: compression level used by zstd compression
    • minInputLen: minimum length of data which are compresed, input <= minInputLen is not compressed

Provider id can be:

  • 0 - no compression, the function returns nil, nil
  • 1 - zstd compression
  • 2 - s2 compression
  • 3 - lz4 compression

If the engine is created in the following way compression.NewEngine(1,nil) the data are compressed with Zstd method.

Other compression providers can be easily added to the Engine:

  • compression.Engine.AddDefaultProvider(compression.S2CompressionService) - adds new default compression provider to the engine; since now data are compressed using the s2 provider. The old inputs (alredy compressed with zstd) can be decompressed becasue the engine contains two providers: zstd, s2

  • compression.Engine.AddProvider(compression.Lz4CompressionService) - adds new compression provider to the engine; the default provider is not changed

The defult size of not compressed input can be easily changed:

  • compression.NewEngine(providerID, nil).SetMinInputSize(2048) -since now input <= 2 KB is not compressed
  • compression.NewEngine(providerID byte, map[string]interface {} {"minInputLen": 2048}

If the provider is already added to the Engine the default provider can be selected by the provider id

  • compression.Engine.SetDefaultProvider(2)
  • compression.Engine.SetDefaultProvider(ProviderIDS2)

How does the Engine know which provider should be used to decompress data?

There is added a footer to the compressed data. The footer size is:

  • 1 byte for NoCompressionService
    • compressed_data + provider_id(1 byte)
  • 9 bytes for other compression providers
    • compressed_data + size_of_not_compressed_data(8 bytes) + provider_id(1 byte)

How to implement a new compression provider?

Compression provider has to implement an interface compression.Provider by implementing its methods

  • Compress(src []byte) ([]byte, error)
  • Decompress(src []byte, dstSize int) ([]byte, error)
  • GetID() byte
  • Configure(params CompressionParams) error

Provider cannot manage the footer. The footer is manged by the Engine. The Engine:

  • adds footer to compressed data,
  • extracts the compressed data and footer from the input; the providers is suplied with the input without the footer.

How change compression level for ZSTD?

Providers can be configured using compressionParameters. For example:

NewEngine(ProviderIDZstd, map[string]interface{}{
		CompressionParamLevel: 5,
	})

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound      = errors.New("key not found")
	ErrWrongDataType = errors.New("data in wrong format")
)

Errors

Functions

This section is empty.

Types

type Cache

type Cache[T any] struct {
	// contains filtered or unexported fields
}

Cache is an implementation of a cache (key-value store). It needs to be provided with cache engine.

func MakeCache

func MakeCache[T any](engine CacheEngine) *Cache[T]

MakeCache creates cache with provided engine

func (*Cache[T]) CountPredicate added in v1.0.2

func (c *Cache[T]) CountPredicate(pred Predicate) (int, error)

CountPredicate counts cache keys satisfying the given predicate

func (*Cache[T]) CountRegExp added in v1.0.1

func (c *Cache[T]) CountRegExp(pattern string) (int, error)

CountRegExp counts all keys matching the supplied regexp

func (*Cache[T]) Delete added in v1.1.0

func (c *Cache[T]) Delete(key string) error

Delete removes a key from cache

func (*Cache[T]) DeletePredicate added in v1.0.2

func (c *Cache[T]) DeletePredicate(pred Predicate) (int, error)

DeletePredicate deletes all keys matching the supplied predicate, returns number of deleted keys

func (*Cache[T]) DeleteRegExp

func (c *Cache[T]) DeleteRegExp(pattern string) (int, error)

DeleteRegExp deletes all keys matching the supplied regexp, returns number of deleted keys

func (*Cache[T]) DeleteWithPrefix

func (c *Cache[T]) DeleteWithPrefix(prefix string) (int, error)

DeleteWithPrefix removes all keys that start with given prefix, returns number of deleted keys

func (*Cache[T]) Get added in v1.1.0

func (c *Cache[T]) Get(key string) (*T, error)

Get gets a cached value by key

func (*Cache[T]) GetIndirect added in v1.0.3

func (c *Cache[T]) GetIndirect(key string, linkResolver func(*T) string) (*T, error)

GetIndirect gets a key value following any intermediary links

func (*Cache[T]) GetOrCompute

func (c *Cache[T]) GetOrCompute(key string, evaluator func() (*T, error)) (*T, error)

GetOrCompute tries to get value from cache. If not found, it computes the value using provided evaluator function and stores it into cache. In case of other errors the value is evaluated but not stored in the cache.

func (*Cache[T]) GetOrComputeEx added in v1.0.3

func (c *Cache[T]) GetOrComputeEx(key string, evaluator func() (*T, error), validator func(*T) bool, linkResolver func(*T) string, linkGenerator func(*T) *T, writeApprover func(*T) bool) (*T, error)

GetOrComputeEx tries to get value from cache. If not found, it computes the value using provided evaluator function and stores it into cache. In case of other errors the value is evaluated but not stored in the cache. Additional parameters (can be nil): validator - validates cache records, on false evaluator will be run again (new results will not be validated) linkResolver - checks if cached value is a link and returns the key it's pointing to linkGenerator - generates intermediate link value if needed when a new record is inserted writeApprover - decides if new value is to be written in the cache

func (*Cache[T]) Keys added in v1.1.0

func (c *Cache[T]) Keys() ([]string, error)

Keys returns all the keys in cache

func (*Cache[T]) Peek added in v1.1.0

func (c *Cache[T]) Peek(key string) (*T, error)

Peek gets a value by given key and does not change it's "lruness"

func (*Cache[T]) Purge added in v1.1.0

func (c *Cache[T]) Purge() error

Purge removes all records from the cache

func (*Cache[T]) Set added in v1.1.0

func (c *Cache[T]) Set(key string, value *T) error

Set stores a key-value pair into cache

func (*Cache[T]) SetIndirect added in v1.0.3

func (c *Cache[T]) SetIndirect(key string, value *T, linkResolver func(*T) string, linkGenerator func(*T) *T) error

SetIndirect sets cache key including intermediary links

type CacheEngine

type CacheEngine interface {
	Get(key string) (interface{}, error)
	Peek(key string) (interface{}, error)
	Set(key string, value interface{}) error
	Delete(key string) error
	Keys() ([]string, error)
	Purge() error
}

CacheEngine is an interface for cache engine (e.g. in-memory cache or Redis Cache)

type CacheWithSubcache

type CacheWithSubcache[T any] struct {
	Cache    *Cache[T]
	Subcache *Cache[T]
}

CacheWithSubcache is a Cache with L1 subcache.

func (*CacheWithSubcache[T]) Delete

func (cs *CacheWithSubcache[T]) Delete(key string) error

Delete removes a key from cache

func (*CacheWithSubcache[T]) Get

func (cs *CacheWithSubcache[T]) Get(key string) (interface{}, error)

Get gets a cached value by key

func (*CacheWithSubcache[T]) Keys

func (cs *CacheWithSubcache[T]) Keys() ([]string, error)

Keys returns a slice of all keys in the cache

func (*CacheWithSubcache[T]) Peek

func (cs *CacheWithSubcache[T]) Peek(key string) (interface{}, error)

Peek gets a cached key value without side-effects (i.e. without adding to L1 cache)

func (*CacheWithSubcache[T]) Purge

func (cs *CacheWithSubcache[T]) Purge() error

Purge removes all the records from the cache

func (*CacheWithSubcache[T]) Set

func (cs *CacheWithSubcache[T]) Set(key string, value interface{}) error

Set stores a key-value pair into cache

type DummyLogger

type DummyLogger struct{}

DummyLogger is implementation of Logger that does not log anything

func (DummyLogger) Error

func (d DummyLogger) Error(...interface{})

Error does nothing

func (DummyLogger) Print

func (d DummyLogger) Print(...interface{})

Print does nothing

func (DummyLogger) Warn

func (d DummyLogger) Warn(...interface{})

Warn does nothing

type LRUCache

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

LRUCache is a wrapper of hashicorp's golang-lru cache which implements cachier.Cache interface

func NewLRUCache

func NewLRUCache(
	size int,
	marshal func(value interface{}) ([]byte, error),
	unmarshal func(b []byte, value *interface{}) error,
	compressionEngine *compression.Engine,
) (*LRUCache, error)

NewLRUCache is a constructor that creates LRU cache of given size If you want to compress the entries before storing them the marshal and unmarshal functions must be provided If the compression.Engine is nil the marshal and unmarshal functions are not used

func NewLRUCacheWithLogger

func NewLRUCacheWithLogger(
	size int,
	marshal func(value interface{}) ([]byte, error),
	unmarshal func(b []byte, value *interface{}) error,
	logger Logger,
	compressionEngine *compression.Engine,
) (*LRUCache, error)

func (*LRUCache) Delete

func (lc *LRUCache) Delete(key string) error

Delete removes a key from cache

func (*LRUCache) Get

func (lc *LRUCache) Get(key string) (v interface{}, err error)

Get gets a value by given key

func (*LRUCache) Keys

func (lc *LRUCache) Keys() ([]string, error)

Keys returns all the keys in cache

func (*LRUCache) Peek

func (lc *LRUCache) Peek(key string) (v interface{}, err error)

Peek gets a value by given key and does not change it's "lruness"

func (*LRUCache) Purge

func (lc *LRUCache) Purge() error

Purge removes all records from the cache

func (*LRUCache) Set

func (lc *LRUCache) Set(key string, value interface{}) (err error)

Set stores given key-value pair into cache

type Logger

type Logger interface {
	Error(...interface{})
	Warn(...interface{})
	Print(...interface{})
}

Logger is interface for logging

type Predicate added in v1.0.2

type Predicate func(string) bool

Predicate evaluates a condition on the input string

type RedisCache

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

RedisCache implements cachier.CacheTTL interface using redis storage

func NewRedisCache

func NewRedisCache(
	redisClient *redis.Client,
	keyPrefix string,
	marshal func(value interface{}) ([]byte, error),
	unmarshal func(b []byte, value *interface{}) error,
	ttl time.Duration,
	compressionEngine *compression.Engine,
) *RedisCache

NewRedisCache is a constructor that creates a RedisCache

func NewRedisCacheWithLogger

func NewRedisCacheWithLogger(
	redisClient *redis.Client,
	keyPrefix string,
	marshal func(value interface{}) ([]byte, error),
	unmarshal func(b []byte, value *interface{}) error,
	ttl time.Duration,
	logger Logger,
	compressionEngine *compression.Engine,
) *RedisCache

NewRedisCacheWithLogger is a constructor that creates a RedisCache

func (*RedisCache) Delete

func (rc *RedisCache) Delete(key string) error

Delete removes a key from cache

func (*RedisCache) Get

func (rc *RedisCache) Get(key string) (v interface{}, err error)

Get gets a cached value by key

func (*RedisCache) Keys

func (rc *RedisCache) Keys() ([]string, error)

Keys returns all the keys in the cache

func (*RedisCache) Peek

func (rc *RedisCache) Peek(key string) (interface{}, error)

Peek gets a cached value by key without any sideeffects (identical as Get in this implementation)

func (*RedisCache) Purge

func (rc *RedisCache) Purge() error

Purge removes all the records from the cache

func (*RedisCache) Set

func (rc *RedisCache) Set(key string, value interface{}) (err error)

Set stores a key-value pair into cache

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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