Files
grafana/pkg/infra/remotecache/remotecache.go

132 lines
3.6 KiB
Go
Raw Normal View History

2019-03-08 20:49:16 +01:00
package remotecache
2019-02-14 23:13:46 +01:00
import (
"bytes"
2019-03-05 15:34:51 +01:00
"context"
2019-02-14 23:13:46 +01:00
"encoding/gob"
"errors"
2019-02-23 16:12:37 +01:00
"time"
2019-02-14 23:13:46 +01:00
"github.com/grafana/grafana/pkg/infra/log"
2019-02-14 23:13:46 +01:00
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
2019-02-14 23:13:46 +01:00
)
var (
2019-03-14 08:57:38 +01:00
// ErrCacheItemNotFound is returned if cache does not exist
2019-02-14 23:13:46 +01:00
ErrCacheItemNotFound = errors.New("cache item not found")
2019-03-14 08:57:38 +01:00
// ErrInvalidCacheType is returned if the type is invalid
ErrInvalidCacheType = errors.New("invalid remote cache name")
2019-03-14 09:22:03 +01:00
defaultMaxCacheExpiration = time.Hour * 24
2019-02-14 23:13:46 +01:00
)
func init() {
2019-03-08 20:49:16 +01:00
registry.RegisterService(&RemoteCache{})
2019-02-14 23:13:46 +01:00
}
2019-03-05 15:34:51 +01:00
// CacheStorage allows the caller to set, get and delete items in the cache.
// Cached items are stored as byte arrays and marshalled using "encoding/gob"
// so any struct added to the cache needs to be registered with `remotecache.Register`
2019-03-14 09:23:35 +01:00
// ex `remotecache.Register(CacheableStruct{})``
2019-03-05 15:34:51 +01:00
type CacheStorage interface {
// Get reads object from Cache
Get(key string) (interface{}, error)
2019-03-14 09:22:03 +01:00
// Set sets an object into the cache. if `expire` is set to zero it will default to 24h
2019-03-05 15:34:51 +01:00
Set(key string, value interface{}, expire time.Duration) error
// Delete object from cache
Delete(key string) error
}
2019-03-08 20:49:16 +01:00
// RemoteCache allows Grafana to cache data outside its own process
type RemoteCache struct {
2019-03-05 15:34:51 +01:00
log log.Logger
2019-03-11 10:44:16 +01:00
client CacheStorage
2019-03-05 15:34:51 +01:00
SQLStore *sqlstore.SqlStore `inject:""`
Cfg *setting.Cfg `inject:""`
}
2019-03-14 09:22:03 +01:00
// Get reads object from Cache
2019-03-11 10:44:16 +01:00
func (ds *RemoteCache) Get(key string) (interface{}, error) {
return ds.client.Get(key)
}
2019-03-14 09:22:03 +01:00
// Set sets an object into the cache. if `expire` is set to zero it will default to 24h
2019-03-11 10:44:16 +01:00
func (ds *RemoteCache) Set(key string, value interface{}, expire time.Duration) error {
2019-03-14 09:22:03 +01:00
if expire == 0 {
expire = defaultMaxCacheExpiration
}
2019-03-11 10:44:16 +01:00
return ds.client.Set(key, value, expire)
}
2019-03-14 09:22:03 +01:00
// Delete object from cache
2019-03-11 10:44:16 +01:00
func (ds *RemoteCache) Delete(key string) error {
return ds.client.Delete(key)
}
2019-02-14 23:13:46 +01:00
// Init initializes the service
2019-03-08 20:49:16 +01:00
func (ds *RemoteCache) Init() error {
ds.log = log.New("cache.remote")
2019-03-14 08:57:38 +01:00
var err error
ds.client, err = createClient(ds.Cfg.RemoteCacheOptions, ds.SQLStore)
return err
2019-02-14 23:13:46 +01:00
}
2019-03-08 20:49:16 +01:00
// Run start the backend processes for cache clients
func (ds *RemoteCache) Run(ctx context.Context) error {
// create new interface if more clients need GC jobs
2019-03-11 10:44:16 +01:00
backgroundjob, ok := ds.client.(registry.BackgroundService)
2019-03-05 15:34:51 +01:00
if ok {
return backgroundjob.Run(ctx)
}
<-ctx.Done()
return ctx.Err()
}
2019-03-14 08:57:38 +01:00
func createClient(opts *setting.RemoteCacheOptions, sqlstore *sqlstore.SqlStore) (CacheStorage, error) {
2019-03-14 09:27:41 +01:00
if opts.Name == redisCacheType {
return newRedisStorage(opts)
2019-02-15 09:48:32 +01:00
}
2019-03-14 09:27:41 +01:00
if opts.Name == memcachedCacheType {
2019-03-14 08:57:38 +01:00
return newMemcachedStorage(opts), nil
}
2019-03-14 09:27:41 +01:00
if opts.Name == databaseCacheType {
2019-03-14 08:57:38 +01:00
return newDatabaseCache(sqlstore), nil
2019-02-15 09:48:32 +01:00
}
2019-03-14 08:57:38 +01:00
return nil, ErrInvalidCacheType
2019-02-15 09:48:32 +01:00
}
2019-03-05 15:34:51 +01:00
// Register records a type, identified by a value for that type, under its
// internal type name. That name will identify the concrete type of a value
// sent or received as an interface variable. Only types that will be
// transferred as implementations of interface values need to be registered.
// Expecting to be used only during initialization, it panics if the mapping
// between types and names is not a bijection.
func Register(value interface{}) {
gob.Register(value)
2019-02-14 23:13:46 +01:00
}
type cachedItem struct {
Val interface{}
2019-02-14 23:13:46 +01:00
}
func encodeGob(item *cachedItem) ([]byte, error) {
2019-02-14 23:13:46 +01:00
buf := bytes.NewBuffer(nil)
err := gob.NewEncoder(buf).Encode(item)
return buf.Bytes(), err
}
func decodeGob(data []byte, out *cachedItem) error {
2019-02-14 23:13:46 +01:00
buf := bytes.NewBuffer(data)
return gob.NewDecoder(buf).Decode(&out)
}