github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/cache/cache.go (about)

     1  package cache
     2  
     3  import (
     4  	"runtime"
     5  	"sync"
     6  	"time"
     7  )
     8  
     9  type Cache struct {
    10  	defaultExpiration time.Duration
    11  	items             map[string]Item
    12  	mu                sync.RWMutex
    13  	onEvicted         func(string, any)
    14  	j                 *janitor
    15  }
    16  
    17  type Item struct {
    18  	//data
    19  	Data any
    20  	//ttl time.UnixNano.Expiration of Item,if it is -1,it will be not Expired
    21  	Ttl int64
    22  }
    23  
    24  func (item *Item) Expired() bool {
    25  	if item.Ttl == -1 {
    26  		//用户
    27  		return false
    28  	}
    29  	return time.Now().UnixNano() > item.Ttl
    30  }
    31  
    32  func New() *Cache {
    33  	return NewWithExpiration(0)
    34  }
    35  
    36  func NewWithExpiration(expiration time.Duration) *Cache {
    37  	return NewWithExpirationAndCleanupInterval(expiration, 0)
    38  }
    39  
    40  func NewWithCleanupInterval(cleanupInterval time.Duration) *Cache {
    41  	return NewWithExpirationAndCleanupInterval(0, cleanupInterval)
    42  }
    43  func NewWithExpirationAndCleanupInterval(defaultExpiration, cleanupInterval time.Duration) *Cache {
    44  	if defaultExpiration == 0 {
    45  		defaultExpiration = -1
    46  	}
    47  	ch := make(chan bool)
    48  	c := &Cache{
    49  		defaultExpiration: defaultExpiration,
    50  		items:             make(map[string]Item),
    51  		j: &janitor{
    52  			Interval: 1 * time.Second,
    53  			stop:     ch,
    54  		},
    55  	}
    56  	//启动清理协程
    57  	go func() {
    58  		c.runCleanup(cleanupInterval)
    59  		runtime.SetFinalizer(c, stopJanitor)
    60  	}()
    61  	return c
    62  }
    63  
    64  type janitor struct {
    65  	Interval time.Duration
    66  	stop     chan bool
    67  }
    68  
    69  func (c *Cache) runCleanup(cleanupInterval time.Duration) {
    70  	if cleanupInterval == 0 {
    71  		cleanupInterval = 500 * time.Millisecond
    72  	}
    73  	ticker := time.NewTicker(cleanupInterval)
    74  	for {
    75  		select {
    76  		case <-ticker.C:
    77  			c.DeleteExpired()
    78  		case <-c.j.stop:
    79  			ticker.Stop()
    80  			return
    81  		}
    82  	}
    83  }
    84  
    85  func stopJanitor(c *Cache) {
    86  	c.j.stop <- true
    87  }
    88  
    89  func (c *Cache) DeleteExpired() {
    90  	l := len(c.items)
    91  	if l < 1 {
    92  		return
    93  	}
    94  	cloneMap := map[string]Item{}
    95  	c.mu.Lock()
    96  	for k, v := range c.items {
    97  		cloneMap[k] = v
    98  	}
    99  	c.mu.Unlock()
   100  
   101  	ch := make(chan int8, len(c.items))
   102  	for key, item := range cloneMap {
   103  		go func(k string, i Item) {
   104  			if i.Expired() {
   105  				c.mu.Lock()
   106  				delete(c.items, k)
   107  				c.mu.Unlock()
   108  			}
   109  			ch <- int8(1)
   110  		}(key, item)
   111  	}
   112  }