github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/lib/cache/cache.go (about) 1 // Package cache implements a simple cache where the entries are 2 // expired after a given time (5 minutes of disuse by default). 3 package cache 4 5 import ( 6 "sync" 7 "time" 8 ) 9 10 // Cache holds values indexed by string, but expired after a given (5 11 // minutes by default). 12 type Cache struct { 13 mu sync.Mutex 14 cache map[string]*cacheEntry 15 expireRunning bool 16 expireDuration time.Duration // expire the cache entry when it is older than this 17 expireInterval time.Duration // interval to run the cache expire 18 } 19 20 // New creates a new cache with the default expire duration and interval 21 func New() *Cache { 22 return &Cache{ 23 cache: map[string]*cacheEntry{}, 24 expireRunning: false, 25 expireDuration: 300 * time.Second, 26 expireInterval: 60 * time.Second, 27 } 28 } 29 30 // cacheEntry is stored in the cache 31 type cacheEntry struct { 32 value interface{} // cached item 33 err error // creation error 34 key string // key 35 lastUsed time.Time // time used for expiry 36 } 37 38 // CreateFunc is called to create new values. If the create function 39 // returns an error it will be cached if ok is true, otherwise the 40 // error will just be returned, allowing negative caching if required. 41 type CreateFunc func(key string) (value interface{}, ok bool, error error) 42 43 // used marks an entry as accessed now and kicks the expire timer off 44 // should be called with the lock held 45 func (c *Cache) used(entry *cacheEntry) { 46 entry.lastUsed = time.Now() 47 if !c.expireRunning { 48 time.AfterFunc(c.expireInterval, c.cacheExpire) 49 c.expireRunning = true 50 } 51 } 52 53 // Get gets a value named key either from the cache or creates it 54 // afresh with the create function. 55 func (c *Cache) Get(key string, create CreateFunc) (value interface{}, err error) { 56 c.mu.Lock() 57 entry, ok := c.cache[key] 58 if !ok { 59 c.mu.Unlock() // Unlock in case Get is called recursively 60 value, ok, err = create(key) 61 if err != nil && !ok { 62 return value, err 63 } 64 entry = &cacheEntry{ 65 value: value, 66 key: key, 67 err: err, 68 } 69 c.mu.Lock() 70 c.cache[key] = entry 71 } 72 defer c.mu.Unlock() 73 c.used(entry) 74 return entry.value, entry.err 75 } 76 77 // Put puts an value named key into the cache 78 func (c *Cache) Put(key string, value interface{}) { 79 c.mu.Lock() 80 defer c.mu.Unlock() 81 entry := &cacheEntry{ 82 value: value, 83 key: key, 84 } 85 c.used(entry) 86 c.cache[key] = entry 87 } 88 89 // GetMaybe returns the key and true if found, nil and false if not 90 func (c *Cache) GetMaybe(key string) (value interface{}, found bool) { 91 c.mu.Lock() 92 defer c.mu.Unlock() 93 entry, found := c.cache[key] 94 if !found { 95 return nil, found 96 } 97 c.used(entry) 98 return entry.value, found 99 } 100 101 // cacheExpire expires any entries that haven't been used recently 102 func (c *Cache) cacheExpire() { 103 c.mu.Lock() 104 defer c.mu.Unlock() 105 now := time.Now() 106 for key, entry := range c.cache { 107 if now.Sub(entry.lastUsed) > c.expireDuration { 108 delete(c.cache, key) 109 } 110 } 111 if len(c.cache) != 0 { 112 time.AfterFunc(c.expireInterval, c.cacheExpire) 113 c.expireRunning = true 114 } else { 115 c.expireRunning = false 116 } 117 } 118 119 // Clear removes everything from the cahce 120 func (c *Cache) Clear() { 121 c.mu.Lock() 122 for k := range c.cache { 123 delete(c.cache, k) 124 } 125 c.mu.Unlock() 126 } 127 128 // Entries returns the number of entries in the cache 129 func (c *Cache) Entries() int { 130 c.mu.Lock() 131 entries := len(c.cache) 132 c.mu.Unlock() 133 return entries 134 }