Files
remark42/backend/vendor/github.com/go-pkgz/rest/cache/cache.go
T

105 lines
2.9 KiB
Go

// Package cache implements a wrapper on top of hashicorp/golang-lru with guava-style loader func.
// In addition for Get (i.e. load from cache if found and put to cache if absent) it adds a Key struct
// with record ID, site ID and invalidation scopes. Scopes used to evict matching records.
// Additional limits added for total cache size, mac number of keys and max size of the value. If exceeded it won't
// put to cache but will call loader func.
// Usually the cache involved on []byte response level, i.e. post-marshaling right before response's send.
package cache
import (
"strings"
"github.com/pkg/errors"
)
// LoadingCache defines interface for caching
type LoadingCache interface {
Get(key Key, fn func() ([]byte, error)) (data []byte, err error) // load from cache if found or put to cache and return
Flush(req FlusherRequest) // evict matched records
}
type cacheWithOpts interface {
LoadingCache
setMaxValSize(max int) error // max value size, in bytes
setMaxKeys(max int) error // max number of keys
setMaxCacheSize(max int64) error // max cache size (total values) in bytes
setPostFlushFn(postFlushFn func()) error // optional callback after flush
}
// Key for cache
type Key struct {
id string
siteID string
scopes []string
}
// NewKey makes keys for site
func NewKey(site string) Key {
res := Key{siteID: site}
return res
}
// ID sets key id
func (k Key) ID(id string) Key {
k.id = id
return k
}
// Scopes of the key
func (k Key) Scopes(scopes ...string) Key {
k.scopes = scopes
return k
}
// Merge makes full string key from primary key and scopes
func (k Key) Merge() string {
return strings.Join(k.scopes, "$$") + "@@" + k.id + "@@" + k.siteID
}
// ParseKey gets compound key created by Key func and split it to the actual key and scopes
func ParseKey(fullKey string) (Key, error) {
elems := strings.Split(fullKey, "@@")
if len(elems) != 3 {
return Key{}, errors.Errorf("can't parse cache key %s", fullKey)
}
scopes := strings.Split(elems[0], "$$")
if len(scopes) == 1 && scopes[0] == "" {
scopes = []string{}
}
key := Key{
scopes: scopes,
id: elems[1],
siteID: elems[2],
}
return key, nil
}
// FlusherRequest used as input for cache.Flush
type FlusherRequest struct {
siteID string
scopes []string
}
// Flusher makes new FlusherRequest with empty scopes
func Flusher(siteID string) FlusherRequest {
res := FlusherRequest{siteID: siteID}
return res
}
// Scopes adds scopes to FlusherRequest
func (f FlusherRequest) Scopes(scopes ...string) FlusherRequest {
f.scopes = scopes
return f
}
// Nop does nothing for caching, passing fn call only
type Nop struct{}
// Get calls fn, no actual caching
func (n *Nop) Get(key Key, fn func() ([]byte, error)) (data []byte, err error) {
return fn()
}
// Flush does nothing for NoopCache
func (n *Nop) Flush(req FlusherRequest) {}