|
|
|
|
@ -1,6 +1,7 @@ |
|
|
|
|
package distcache |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"context" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/log" |
|
|
|
|
@ -18,32 +19,33 @@ func newDatabaseCache(sqlstore *sqlstore.SqlStore) *databaseCache { |
|
|
|
|
log: log.New("distcache.database"), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//go dc.StartGC() //TODO: start the GC somehow
|
|
|
|
|
return dc |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (dc *databaseCache) Run(ctx context.Context) error { |
|
|
|
|
ticker := time.NewTicker(time.Minute * 10) |
|
|
|
|
for { |
|
|
|
|
select { |
|
|
|
|
case <-ctx.Done(): |
|
|
|
|
return ctx.Err() |
|
|
|
|
case <-ticker.C: |
|
|
|
|
dc.internalRunGC() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var getTime = time.Now |
|
|
|
|
|
|
|
|
|
func (dc *databaseCache) internalRunGC() { |
|
|
|
|
now := getTime().Unix() |
|
|
|
|
sql := `DELETE FROM cache_data WHERE (? - created) >= expire` |
|
|
|
|
sql := `DELETE FROM cache_data WHERE (? - created_at) >= expires AND expires <> 0` |
|
|
|
|
|
|
|
|
|
//EXTRACT(EPOCH FROM NOW()) - created >= expire
|
|
|
|
|
//UNIX_TIMESTAMP(NOW()) - created >= expire
|
|
|
|
|
_, err := dc.SQLStore.NewSession().Exec(sql, now) |
|
|
|
|
if err != nil { |
|
|
|
|
dc.log.Error("failed to run garbage collect", "error", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (dc *databaseCache) StartGC() { |
|
|
|
|
dc.internalRunGC() |
|
|
|
|
|
|
|
|
|
time.AfterFunc(time.Second*10, func() { |
|
|
|
|
dc.StartGC() |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (dc *databaseCache) Get(key string) (interface{}, error) { |
|
|
|
|
cacheHits := []cacheData{} |
|
|
|
|
err := dc.SQLStore.NewSession().Where(`key = ?`, key).Find(&cacheHits) |
|
|
|
|
@ -57,8 +59,10 @@ func (dc *databaseCache) Get(key string) (interface{}, error) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cacheHit = cacheHits[0] |
|
|
|
|
// if Expires is set. Make sure its still valid.
|
|
|
|
|
if cacheHit.Expires > 0 { |
|
|
|
|
if getTime().Unix()-cacheHit.CreatedAt >= cacheHit.Expires { |
|
|
|
|
existedButExpired := getTime().Unix()-cacheHit.CreatedAt >= cacheHit.Expires |
|
|
|
|
if existedButExpired { |
|
|
|
|
dc.Delete(key) |
|
|
|
|
return nil, ErrCacheItemNotFound |
|
|
|
|
} |
|
|
|
|
@ -72,13 +76,6 @@ func (dc *databaseCache) Get(key string) (interface{}, error) { |
|
|
|
|
return item.Val, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type cacheData struct { |
|
|
|
|
Key string |
|
|
|
|
Data []byte |
|
|
|
|
Expires int64 |
|
|
|
|
CreatedAt int64 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (dc *databaseCache) Set(key string, value interface{}, expire time.Duration) error { |
|
|
|
|
item := &cachedItem{Val: value} |
|
|
|
|
data, err := encodeGob(item) |
|
|
|
|
@ -87,22 +84,23 @@ func (dc *databaseCache) Set(key string, value interface{}, expire time.Duration |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
now := getTime().Unix() |
|
|
|
|
|
|
|
|
|
cacheHits := []cacheData{} |
|
|
|
|
err = dc.SQLStore.NewSession().Where(`key = ?`, key).Find(&cacheHits) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var expiresInEpoch int64 |
|
|
|
|
var expiresAtEpoch int64 |
|
|
|
|
if expire != 0 { |
|
|
|
|
expiresInEpoch = int64(expire) / int64(time.Second) |
|
|
|
|
expiresAtEpoch = int64(expire) / int64(time.Second) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
session := dc.SQLStore.NewSession() |
|
|
|
|
// insert or update depending on if item already exist
|
|
|
|
|
if len(cacheHits) > 0 { |
|
|
|
|
_, err = dc.SQLStore.NewSession().Exec("UPDATE cache_data SET data=?, created=?, expire=? WHERE key=?", data, now, expiresInEpoch, key) |
|
|
|
|
_, err = session.Exec("UPDATE cache_data SET data=?, created=?, expire=? WHERE key=?", data, now, expiresAtEpoch, key) |
|
|
|
|
} else { |
|
|
|
|
_, err = dc.SQLStore.NewSession().Exec("INSERT INTO cache_data(key,data,created_at,expires) VALUES(?,?,?,?)", key, data, now, expiresInEpoch) |
|
|
|
|
_, err = session.Exec("INSERT INTO cache_data(key,data,created_at,expires) VALUES(?,?,?,?)", key, data, now, expiresAtEpoch) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return err |
|
|
|
|
@ -110,8 +108,14 @@ func (dc *databaseCache) Set(key string, value interface{}, expire time.Duration |
|
|
|
|
|
|
|
|
|
func (dc *databaseCache) Delete(key string) error { |
|
|
|
|
sql := `DELETE FROM cache_data WHERE key = ?` |
|
|
|
|
|
|
|
|
|
_, err := dc.SQLStore.NewSession().Exec(sql, key) |
|
|
|
|
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type cacheData struct { |
|
|
|
|
Key string |
|
|
|
|
Data []byte |
|
|
|
|
Expires int64 |
|
|
|
|
CreatedAt int64 |
|
|
|
|
} |
|
|
|
|
|