distcache.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package distcache
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/gob"
  6. "errors"
  7. "time"
  8. "github.com/grafana/grafana/pkg/setting"
  9. "github.com/grafana/grafana/pkg/log"
  10. "github.com/grafana/grafana/pkg/services/sqlstore"
  11. "github.com/grafana/grafana/pkg/registry"
  12. )
  13. var (
  14. ErrCacheItemNotFound = errors.New("cache item not found")
  15. )
  16. func init() {
  17. registry.RegisterService(&DistributedCache{})
  18. }
  19. // CacheStorage allows the caller to set, get and delete items in the cache.
  20. // Cached items are stored as byte arrays and marshalled using "encoding/gob"
  21. // so any struct added to the cache needs to be registred with `distcache.Register`
  22. // ex `distcache.Register(CacheableStruct{})``
  23. type CacheStorage interface {
  24. // Get reads object from Cache
  25. Get(key string) (interface{}, error)
  26. // Set sets an object into the cache
  27. Set(key string, value interface{}, expire time.Duration) error
  28. // Delete object from cache
  29. Delete(key string) error
  30. }
  31. // DistributedCache allows Grafana to cache data outside its own process
  32. type DistributedCache struct {
  33. log log.Logger
  34. Client CacheStorage
  35. SQLStore *sqlstore.SqlStore `inject:""`
  36. Cfg *setting.Cfg `inject:""`
  37. }
  38. // Init initializes the service
  39. func (ds *DistributedCache) Init() error {
  40. ds.log = log.New("distributed.cache")
  41. ds.Client = createClient(ds.Cfg.CacheOptions, ds.SQLStore)
  42. return nil
  43. }
  44. func (ds *DistributedCache) Run(ctx context.Context) error {
  45. backgroundjob, ok := ds.Client.(registry.BackgroundService)
  46. if ok {
  47. return backgroundjob.Run(ctx)
  48. }
  49. <-ctx.Done()
  50. return ctx.Err()
  51. }
  52. func createClient(opts *setting.CacheOpts, sqlstore *sqlstore.SqlStore) CacheStorage {
  53. if opts.Name == "redis" {
  54. return newRedisStorage(opts)
  55. }
  56. if opts.Name == "memcached" {
  57. return newMemcachedStorage(opts)
  58. }
  59. return newDatabaseCache(sqlstore)
  60. }
  61. // Register records a type, identified by a value for that type, under its
  62. // internal type name. That name will identify the concrete type of a value
  63. // sent or received as an interface variable. Only types that will be
  64. // transferred as implementations of interface values need to be registered.
  65. // Expecting to be used only during initialization, it panics if the mapping
  66. // between types and names is not a bijection.
  67. func Register(value interface{}) {
  68. gob.Register(value)
  69. }
  70. type cachedItem struct {
  71. Val interface{}
  72. }
  73. func encodeGob(item *cachedItem) ([]byte, error) {
  74. buf := bytes.NewBuffer(nil)
  75. err := gob.NewEncoder(buf).Encode(item)
  76. return buf.Bytes(), err
  77. }
  78. func decodeGob(data []byte, out *cachedItem) error {
  79. buf := bytes.NewBuffer(data)
  80. return gob.NewDecoder(buf).Decode(&out)
  81. }