github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/cache/namedmemcache/named_cache.go (about)

     1  // Copyright 2018 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package namedmemcache provides a memory cache with a named lock. This is suitable
    15  // for situations where creating the cached resource can be time consuming or otherwise
    16  // resource hungry, or in situations where a "once only per key" is a requirement.
    17  package namedmemcache
    18  
    19  import (
    20  	"sync"
    21  
    22  	"github.com/BurntSushi/locker"
    23  )
    24  
    25  // Cache holds the cached values.
    26  type Cache struct {
    27  	nlocker *locker.Locker
    28  	cache   map[string]cacheEntry
    29  	mu      sync.RWMutex
    30  }
    31  
    32  type cacheEntry struct {
    33  	value interface{}
    34  	err   error
    35  }
    36  
    37  // New creates a new cache.
    38  func New() *Cache {
    39  	return &Cache{
    40  		nlocker: locker.NewLocker(),
    41  		cache:   make(map[string]cacheEntry),
    42  	}
    43  }
    44  
    45  // Clear clears the cache state.
    46  func (c *Cache) Clear() {
    47  	c.mu.Lock()
    48  	defer c.mu.Unlock()
    49  
    50  	c.cache = make(map[string]cacheEntry)
    51  	c.nlocker = locker.NewLocker()
    52  }
    53  
    54  // GetOrCreate tries to get the value with the given cache key, if not found
    55  // create will be called and cached.
    56  // This method is thread safe. It also guarantees that the create func for a given
    57  // key is invoked only once for this cache.
    58  func (c *Cache) GetOrCreate(key string, create func() (interface{}, error)) (interface{}, error) {
    59  	c.mu.RLock()
    60  	entry, found := c.cache[key]
    61  	c.mu.RUnlock()
    62  
    63  	if found {
    64  		return entry.value, entry.err
    65  	}
    66  
    67  	c.nlocker.Lock(key)
    68  	defer c.nlocker.Unlock(key)
    69  
    70  	// Create it.
    71  	value, err := create()
    72  
    73  	c.mu.Lock()
    74  	c.cache[key] = cacheEntry{value: value, err: err}
    75  	c.mu.Unlock()
    76  
    77  	return value, err
    78  }