storage_memory.go 2.5 KB

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