github.com/artpar/rclone@v1.67.3/backend/cache/storage_memory.go (about)

     1  //go:build !plan9 && !js
     2  
     3  package cache
     4  
     5  import (
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/artpar/rclone/fs"
    12  	cache "github.com/patrickmn/go-cache"
    13  )
    14  
    15  // Memory is a wrapper of transient storage for a go-cache store
    16  type Memory struct {
    17  	db *cache.Cache
    18  }
    19  
    20  // NewMemory builds this cache storage
    21  // defaultExpiration will set the expiry time of chunks in this storage
    22  func NewMemory(defaultExpiration time.Duration) *Memory {
    23  	mem := &Memory{}
    24  	err := mem.Connect(defaultExpiration)
    25  	if err != nil {
    26  		fs.Errorf("cache", "can't open ram connection: %v", err)
    27  	}
    28  
    29  	return mem
    30  }
    31  
    32  // Connect will create a connection for the storage
    33  func (m *Memory) Connect(defaultExpiration time.Duration) error {
    34  	m.db = cache.New(defaultExpiration, -1)
    35  	return nil
    36  }
    37  
    38  // HasChunk confirms the existence of a single chunk of an object
    39  func (m *Memory) HasChunk(cachedObject *Object, offset int64) bool {
    40  	key := cachedObject.abs() + "-" + strconv.FormatInt(offset, 10)
    41  	_, found := m.db.Get(key)
    42  	return found
    43  }
    44  
    45  // GetChunk will retrieve a single chunk which belongs to a cached object or an error if it doesn't find it
    46  func (m *Memory) GetChunk(cachedObject *Object, offset int64) ([]byte, error) {
    47  	key := cachedObject.abs() + "-" + strconv.FormatInt(offset, 10)
    48  	var data []byte
    49  
    50  	if x, found := m.db.Get(key); found {
    51  		data = x.([]byte)
    52  		return data, nil
    53  	}
    54  
    55  	return nil, fmt.Errorf("couldn't get cached object data at offset %v", offset)
    56  }
    57  
    58  // AddChunk adds a new chunk of a cached object
    59  func (m *Memory) AddChunk(fp string, data []byte, offset int64) error {
    60  	return m.AddChunkAhead(fp, data, offset, time.Second)
    61  }
    62  
    63  // AddChunkAhead adds a new chunk of a cached object
    64  func (m *Memory) AddChunkAhead(fp string, data []byte, offset int64, t time.Duration) error {
    65  	key := fp + "-" + strconv.FormatInt(offset, 10)
    66  	m.db.Set(key, data, cache.DefaultExpiration)
    67  
    68  	return nil
    69  }
    70  
    71  // CleanChunksByAge will cleanup on a cron basis
    72  func (m *Memory) CleanChunksByAge(chunkAge time.Duration) {
    73  	m.db.DeleteExpired()
    74  }
    75  
    76  // CleanChunksByNeed will cleanup chunks after the FS passes a specific chunk
    77  func (m *Memory) CleanChunksByNeed(offset int64) {
    78  	for key := range m.db.Items() {
    79  		sepIdx := strings.LastIndex(key, "-")
    80  		keyOffset, err := strconv.ParseInt(key[sepIdx+1:], 10, 64)
    81  		if err != nil {
    82  			fs.Errorf("cache", "couldn't parse offset entry %v", key)
    83  			continue
    84  		}
    85  
    86  		if keyOffset < offset {
    87  			m.db.Delete(key)
    88  		}
    89  	}
    90  }
    91  
    92  // CleanChunksBySize will cleanup chunks after the total size passes a certain point
    93  func (m *Memory) CleanChunksBySize(maxSize int64) {
    94  	// NOOP
    95  }