mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +01:00 
			
		
		
		
	Updates #cleanup Change-Id: Ib3a33a7609530ef8c9f3f58fc607a61e8655c4b5 Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
		
			
				
	
	
		
			82 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| package cache
 | |
| 
 | |
| import (
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| // Single is a simple in-memory cache that stores a single value until a
 | |
| // defined time before it is re-fetched. It also supports returning a
 | |
| // previously-expired value if refreshing the value in the cache fails.
 | |
| //
 | |
| // Single is not safe for concurrent use.
 | |
| type Single[K comparable, V any] struct {
 | |
| 	key       K
 | |
| 	val       V
 | |
| 	goodUntil time.Time
 | |
| 	timeNow   func() time.Time // for tests
 | |
| 
 | |
| 	// ServeExpired indicates that if an error occurs when filling the
 | |
| 	// cache, an expired value can be returned instead of an error.
 | |
| 	//
 | |
| 	// This value should only be set when this struct is created.
 | |
| 	ServeExpired bool
 | |
| }
 | |
| 
 | |
| var _ Cache[int, int] = (*Single[int, int])(nil)
 | |
| 
 | |
| // Get will return the cached value, if any, or fill the cache by calling f and
 | |
| // return the corresponding value. If f returns an error and c.ServeExpired is
 | |
| // true, then a previous expired value can be returned with no error.
 | |
| func (c *Single[K, V]) Get(key K, f FillFunc[V]) (V, error) {
 | |
| 	var now time.Time
 | |
| 	if c.timeNow != nil {
 | |
| 		now = c.timeNow()
 | |
| 	} else {
 | |
| 		now = time.Now()
 | |
| 	}
 | |
| 
 | |
| 	if c.key == key && now.Before(c.goodUntil) {
 | |
| 		return c.val, nil
 | |
| 	}
 | |
| 
 | |
| 	// Re-fill cached entry
 | |
| 	val, until, err := f()
 | |
| 	if err == nil {
 | |
| 		c.key = key
 | |
| 		c.val = val
 | |
| 		c.goodUntil = until
 | |
| 		return val, nil
 | |
| 	}
 | |
| 
 | |
| 	// Never serve an expired entry for the wrong key.
 | |
| 	if c.key == key && c.ServeExpired && !c.goodUntil.IsZero() {
 | |
| 		return c.val, nil
 | |
| 	}
 | |
| 
 | |
| 	var zero V
 | |
| 	return zero, err
 | |
| }
 | |
| 
 | |
| // Forget implements Cache.
 | |
| func (c *Single[K, V]) Forget(key K) {
 | |
| 	if c.key != key {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	c.Empty()
 | |
| }
 | |
| 
 | |
| // Empty implements Cache.
 | |
| func (c *Single[K, V]) Empty() {
 | |
| 	c.goodUntil = time.Time{}
 | |
| 
 | |
| 	var zeroKey K
 | |
| 	c.key = zeroKey
 | |
| 
 | |
| 	var zeroVal V
 | |
| 	c.val = zeroVal
 | |
| }
 |