...

Source file src/github.com/jellydator/ttlcache/v3/item.go

Documentation: github.com/jellydator/ttlcache/v3

     1  package ttlcache
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  const (
     9  	// NoTTL indicates that an item should never expire.
    10  	NoTTL time.Duration = -1
    11  
    12  	// PreviousOrDefaultTTL indicates that existing TTL of item should be used
    13  	// default TTL will be used as fallback if item doesn't exist
    14  	PreviousOrDefaultTTL time.Duration = -2
    15  
    16  	// DefaultTTL indicates that the default TTL value of the cache
    17  	// instance should be used.
    18  	DefaultTTL time.Duration = 0
    19  )
    20  
    21  // Item holds all the information that is associated with a single
    22  // cache value.
    23  type Item[K comparable, V any] struct {
    24  	// the mutex needs to be locked only when:
    25  	// - data fields are being read inside accessor methods
    26  	// - data fields are being updated
    27  	// when data fields are being read in one of the cache's
    28  	// methods, we can be sure that these fields are not modified
    29  	// concurrently since the item list is locked by its own mutex as
    30  	// well, so locking this mutex would be redundant.
    31  	// In other words, this mutex is only useful when these fields
    32  	// are being read from the outside (e.g. in event functions).
    33  	mu         sync.RWMutex
    34  	key        K
    35  	value      V
    36  	ttl        time.Duration
    37  	expiresAt  time.Time
    38  	queueIndex int
    39  	version    int64
    40  }
    41  
    42  // newItem creates a new cache item.
    43  func newItem[K comparable, V any](key K, value V, ttl time.Duration, enableVersionTracking bool) *Item[K, V] {
    44  	item := &Item[K, V]{
    45  		key:   key,
    46  		value: value,
    47  		ttl:   ttl,
    48  	}
    49  
    50  	if !enableVersionTracking {
    51  		item.version = -1
    52  	}
    53  
    54  	item.touch()
    55  
    56  	return item
    57  }
    58  
    59  // update modifies the item's value, TTL, and version.
    60  func (item *Item[K, V]) update(value V, ttl time.Duration) {
    61  	item.mu.Lock()
    62  	defer item.mu.Unlock()
    63  
    64  	item.value = value
    65  
    66  	// update version if enabled
    67  	if item.version > -1 {
    68  		item.version++
    69  	}
    70  
    71  	// no need to update ttl or expiry in this case
    72  	if ttl == PreviousOrDefaultTTL {
    73  		return
    74  	}
    75  
    76  	item.ttl = ttl
    77  
    78  	// reset expiration timestamp because the new TTL may be
    79  	// 0 or below
    80  	item.expiresAt = time.Time{}
    81  	item.touchUnsafe()
    82  }
    83  
    84  // touch updates the item's expiration timestamp.
    85  func (item *Item[K, V]) touch() {
    86  	item.mu.Lock()
    87  	defer item.mu.Unlock()
    88  
    89  	item.touchUnsafe()
    90  }
    91  
    92  // touchUnsafe updates the item's expiration timestamp without
    93  // locking the mutex.
    94  func (item *Item[K, V]) touchUnsafe() {
    95  	if item.ttl <= 0 {
    96  		return
    97  	}
    98  
    99  	item.expiresAt = time.Now().Add(item.ttl)
   100  }
   101  
   102  // IsExpired returns a bool value that indicates whether the item
   103  // is expired.
   104  func (item *Item[K, V]) IsExpired() bool {
   105  	item.mu.RLock()
   106  	defer item.mu.RUnlock()
   107  
   108  	return item.isExpiredUnsafe()
   109  }
   110  
   111  // isExpiredUnsafe returns a bool value that indicates whether the
   112  // the item is expired without locking the mutex
   113  func (item *Item[K, V]) isExpiredUnsafe() bool {
   114  	if item.ttl <= 0 {
   115  		return false
   116  	}
   117  
   118  	return item.expiresAt.Before(time.Now())
   119  }
   120  
   121  // Key returns the key of the item.
   122  func (item *Item[K, V]) Key() K {
   123  	item.mu.RLock()
   124  	defer item.mu.RUnlock()
   125  
   126  	return item.key
   127  }
   128  
   129  // Value returns the value of the item.
   130  func (item *Item[K, V]) Value() V {
   131  	item.mu.RLock()
   132  	defer item.mu.RUnlock()
   133  
   134  	return item.value
   135  }
   136  
   137  // TTL returns the TTL value of the item.
   138  func (item *Item[K, V]) TTL() time.Duration {
   139  	item.mu.RLock()
   140  	defer item.mu.RUnlock()
   141  
   142  	return item.ttl
   143  }
   144  
   145  // ExpiresAt returns the expiration timestamp of the item.
   146  func (item *Item[K, V]) ExpiresAt() time.Time {
   147  	item.mu.RLock()
   148  	defer item.mu.RUnlock()
   149  
   150  	return item.expiresAt
   151  }
   152  
   153  // Version returns the version of the item. It shows the total number of
   154  // changes made to the item.
   155  // If version tracking is disabled, the return value is always -1.
   156  func (item *Item[K, V]) Version() int64 {
   157  	item.mu.RLock()
   158  	defer item.mu.RUnlock()
   159  
   160  	return item.version
   161  }
   162  

View as plain text