reflector.go/store/lru.go

130 lines
3.1 KiB
Go
Raw Normal View History

2020-10-22 18:18:31 +02:00
package store
import (
2021-01-09 05:08:20 +01:00
"time"
2020-10-22 19:49:02 +02:00
"github.com/lbryio/reflector.go/internal/metrics"
2021-01-09 05:08:20 +01:00
"github.com/lbryio/reflector.go/shared"
2020-10-22 18:18:31 +02:00
"github.com/lbryio/lbry.go/v2/extras/errors"
"github.com/lbryio/lbry.go/v2/stream"
"github.com/bluele/gcache"
2020-12-22 21:19:48 +01:00
"github.com/sirupsen/logrus"
2020-10-22 18:18:31 +02:00
)
// LRUStore adds a max cache size and LRU eviction to a BlobStore
type LRUStore struct {
// underlying store
store BlobStore
// lru implementation
lru gcache.Cache
2020-10-22 18:18:31 +02:00
}
// NewLRUStore initialize a new LRUStore
func NewLRUStore(component string, store BlobStore, maxItems int) *LRUStore {
2020-11-20 21:01:33 +01:00
l := &LRUStore{
store: store,
}
l.lru = gcache.New(maxItems).ARC().EvictedFunc(func(key, value interface{}) {
2020-11-20 21:01:33 +01:00
metrics.CacheLRUEvictCount.With(metrics.CacheLabels(l.Name(), component)).Inc()
_ = store.Delete(key.(string))
}).Build()
2020-11-20 21:01:33 +01:00
go func() {
if lstr, ok := store.(lister); ok {
err := l.loadExisting(lstr, maxItems)
if err != nil {
panic(err) // TODO: what should happen here? panic? return nil? just keep going?
}
2020-10-22 18:18:31 +02:00
}
}()
2020-10-22 18:18:31 +02:00
return l
}
2020-10-22 19:49:02 +02:00
// Name is the cache type name
2020-11-20 21:01:33 +01:00
func (l *LRUStore) Name() string {
return "lru_" + l.store.Name()
}
2020-10-22 19:49:02 +02:00
2020-10-22 18:18:31 +02:00
// Has returns whether the blob is in the store, without updating the recent-ness.
func (l *LRUStore) Has(hash string) (bool, error) {
return l.lru.Has(hash), nil
2020-10-22 18:18:31 +02:00
}
// Get returns the blob or an error if the blob doesn't exist.
2021-01-09 05:08:20 +01:00
func (l *LRUStore) Get(hash string) (stream.Blob, shared.BlobTrace, error) {
start := time.Now()
_, err := l.lru.Get(hash)
if err != nil {
2021-01-09 05:08:20 +01:00
return nil, shared.NewBlobTrace(time.Since(start), l.Name()), errors.Err(ErrBlobNotFound)
2020-10-22 18:18:31 +02:00
}
2021-01-09 05:08:20 +01:00
blob, stack, err := l.store.Get(hash)
2020-10-22 18:18:31 +02:00
if errors.Is(err, ErrBlobNotFound) {
// Blob disappeared from underlying store
l.lru.Remove(hash)
}
2021-01-09 05:08:20 +01:00
return blob, stack.Stack(time.Since(start), l.Name()), err
2020-10-22 18:18:31 +02:00
}
// Put stores the blob
func (l *LRUStore) Put(hash string, blob stream.Blob) error {
err := l.store.Put(hash, blob)
if err != nil {
return err
}
l.lru.Set(hash, true)
2020-10-22 18:18:31 +02:00
return nil
}
// PutSD stores the sd blob
func (l *LRUStore) PutSD(hash string, blob stream.Blob) error {
err := l.store.PutSD(hash, blob)
if err != nil {
return err
}
_ = l.lru.Set(hash, true)
2020-10-22 18:18:31 +02:00
return nil
}
// Delete deletes the blob from the store
func (l *LRUStore) Delete(hash string) error {
err := l.store.Delete(hash)
if err != nil {
return err
}
// This must come after store.Delete()
// Remove triggers onEvict function, which also tries to delete blob from store
// We need to delete it manually first so any errors can be propagated up
l.lru.Remove(hash)
return nil
}
// loadExisting imports existing blobs from the underlying store into the LRU cache
func (l *LRUStore) loadExisting(store lister, maxItems int) error {
2020-12-22 21:19:48 +01:00
logrus.Infof("loading at most %d items", maxItems)
2020-10-22 18:18:31 +02:00
existing, err := store.list()
if err != nil {
return err
}
2020-12-22 21:19:48 +01:00
logrus.Infof("read %d files from disk", len(existing))
2020-10-22 18:18:31 +02:00
added := 0
for _, h := range existing {
l.lru.Set(h, true)
2020-10-22 18:18:31 +02:00
added++
if maxItems > 0 && added >= maxItems { // underlying cache is bigger than LRU cache
break
}
}
return nil
}
// Shutdown shuts down the store gracefully
func (l *LRUStore) Shutdown() {
return
}