mirror of
https://github.com/rclone/rclone.git
synced 2024-11-26 18:34:41 +01:00
96 lines
2.5 KiB
Go
96 lines
2.5 KiB
Go
|
// +build !plan9
|
||
|
|
||
|
package cache
|
||
|
|
||
|
import (
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/ncw/rclone/fs"
|
||
|
"github.com/patrickmn/go-cache"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
// Memory is a wrapper of transient storage for a go-cache store
|
||
|
type Memory struct {
|
||
|
ChunkStorage
|
||
|
|
||
|
db *cache.Cache
|
||
|
}
|
||
|
|
||
|
// NewMemory builds this cache storage
|
||
|
// defaultExpiration will set the expiry time of chunks in this storage
|
||
|
func NewMemory(defaultExpiration time.Duration) *Memory {
|
||
|
mem := &Memory{}
|
||
|
err := mem.Connect(defaultExpiration)
|
||
|
if err != nil {
|
||
|
fs.Errorf("cache", "can't open ram connection: %v", err)
|
||
|
}
|
||
|
|
||
|
return mem
|
||
|
}
|
||
|
|
||
|
// Connect will create a connection for the storage
|
||
|
func (m *Memory) Connect(defaultExpiration time.Duration) error {
|
||
|
m.db = cache.New(defaultExpiration, -1)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// HasChunk confirms the existence of a single chunk of an object
|
||
|
func (m *Memory) HasChunk(cachedObject *Object, offset int64) bool {
|
||
|
key := cachedObject.abs() + "-" + strconv.FormatInt(offset, 10)
|
||
|
_, found := m.db.Get(key)
|
||
|
return found
|
||
|
}
|
||
|
|
||
|
// GetChunk will retrieve a single chunk which belongs to a cached object or an error if it doesn't find it
|
||
|
func (m *Memory) GetChunk(cachedObject *Object, offset int64) ([]byte, error) {
|
||
|
key := cachedObject.abs() + "-" + strconv.FormatInt(offset, 10)
|
||
|
var data []byte
|
||
|
|
||
|
if x, found := m.db.Get(key); found {
|
||
|
data = x.([]byte)
|
||
|
return data, nil
|
||
|
}
|
||
|
|
||
|
return nil, errors.Errorf("couldn't get cached object data at offset %v", offset)
|
||
|
}
|
||
|
|
||
|
// AddChunk adds a new chunk of a cached object
|
||
|
func (m *Memory) AddChunk(cachedObject *Object, data []byte, offset int64) error {
|
||
|
return m.AddChunkAhead(cachedObject.abs(), data, offset, time.Second)
|
||
|
}
|
||
|
|
||
|
// AddChunkAhead adds a new chunk of a cached object
|
||
|
func (m *Memory) AddChunkAhead(fp string, data []byte, offset int64, t time.Duration) error {
|
||
|
key := fp + "-" + strconv.FormatInt(offset, 10)
|
||
|
m.db.Set(key, data, cache.DefaultExpiration)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// CleanChunksByAge will cleanup on a cron basis
|
||
|
func (m *Memory) CleanChunksByAge(chunkAge time.Duration) {
|
||
|
m.db.DeleteExpired()
|
||
|
}
|
||
|
|
||
|
// CleanChunksByNeed will cleanup chunks after the FS passes a specific chunk
|
||
|
func (m *Memory) CleanChunksByNeed(offset int64) {
|
||
|
var items map[string]cache.Item
|
||
|
|
||
|
items = m.db.Items()
|
||
|
for key := range items {
|
||
|
sepIdx := strings.LastIndex(key, "-")
|
||
|
keyOffset, err := strconv.ParseInt(key[sepIdx+1:], 10, 64)
|
||
|
if err != nil {
|
||
|
fs.Errorf("cache", "couldn't parse offset entry %v", key)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if keyOffset < offset {
|
||
|
m.db.Delete(key)
|
||
|
}
|
||
|
}
|
||
|
}
|