github.com/kelleygo/clashcore@v1.0.2/common/arc/arc.go (about)

     1  package arc
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	list "github.com/bahlo/generic-list-go"
     8  	"github.com/samber/lo"
     9  )
    10  
    11  //modify from https://github.com/alexanderGugel/arc
    12  
    13  // Option is part of Functional Options Pattern
    14  type Option[K comparable, V any] func(*ARC[K, V])
    15  
    16  func WithSize[K comparable, V any](maxSize int) Option[K, V] {
    17  	return func(a *ARC[K, V]) {
    18  		a.c = maxSize
    19  	}
    20  }
    21  
    22  type ARC[K comparable, V any] struct {
    23  	p     int
    24  	c     int
    25  	t1    *list.List[*entry[K, V]]
    26  	b1    *list.List[*entry[K, V]]
    27  	t2    *list.List[*entry[K, V]]
    28  	b2    *list.List[*entry[K, V]]
    29  	mutex sync.Mutex
    30  	len   int
    31  	cache map[K]*entry[K, V]
    32  }
    33  
    34  // New returns a new Adaptive Replacement Cache (ARC).
    35  func New[K comparable, V any](options ...Option[K, V]) *ARC[K, V] {
    36  	arc := &ARC[K, V]{
    37  		p:     0,
    38  		t1:    list.New[*entry[K, V]](),
    39  		b1:    list.New[*entry[K, V]](),
    40  		t2:    list.New[*entry[K, V]](),
    41  		b2:    list.New[*entry[K, V]](),
    42  		len:   0,
    43  		cache: make(map[K]*entry[K, V]),
    44  	}
    45  
    46  	for _, option := range options {
    47  		option(arc)
    48  	}
    49  	return arc
    50  }
    51  
    52  // Set inserts a new key-value pair into the cache.
    53  // This optimizes future access to this entry (side effect).
    54  func (a *ARC[K, V]) Set(key K, value V) {
    55  	a.mutex.Lock()
    56  	defer a.mutex.Unlock()
    57  
    58  	a.set(key, value)
    59  }
    60  
    61  func (a *ARC[K, V]) set(key K, value V) {
    62  	a.setWithExpire(key, value, time.Unix(0, 0))
    63  }
    64  
    65  // SetWithExpire stores any representation of a response for a given key and given expires.
    66  // The expires time will round to second.
    67  func (a *ARC[K, V]) SetWithExpire(key K, value V, expires time.Time) {
    68  	a.mutex.Lock()
    69  	defer a.mutex.Unlock()
    70  
    71  	a.setWithExpire(key, value, expires)
    72  }
    73  
    74  func (a *ARC[K, V]) setWithExpire(key K, value V, expires time.Time) {
    75  	ent, ok := a.cache[key]
    76  	if !ok {
    77  		a.len++
    78  		ent := &entry[K, V]{key: key, value: value, ghost: false, expires: expires.Unix()}
    79  		a.req(ent)
    80  		a.cache[key] = ent
    81  		return
    82  	}
    83  
    84  	if ent.ghost {
    85  		a.len++
    86  	}
    87  
    88  	ent.value = value
    89  	ent.ghost = false
    90  	ent.expires = expires.Unix()
    91  	a.req(ent)
    92  }
    93  
    94  // Get retrieves a previously via Set inserted entry.
    95  // This optimizes future access to this entry (side effect).
    96  func (a *ARC[K, V]) Get(key K) (value V, ok bool) {
    97  	a.mutex.Lock()
    98  	defer a.mutex.Unlock()
    99  
   100  	ent, ok := a.get(key)
   101  	if !ok {
   102  		return lo.Empty[V](), false
   103  	}
   104  	return ent.value, true
   105  }
   106  
   107  func (a *ARC[K, V]) get(key K) (e *entry[K, V], ok bool) {
   108  	ent, ok := a.cache[key]
   109  	if !ok {
   110  		return ent, false
   111  	}
   112  	a.req(ent)
   113  	return ent, !ent.ghost
   114  }
   115  
   116  // GetWithExpire returns any representation of a cached response,
   117  // a time.Time Give expected expires,
   118  // and a bool set to true if the key was found.
   119  // This method will NOT update the expires.
   120  func (a *ARC[K, V]) GetWithExpire(key K) (V, time.Time, bool) {
   121  	a.mutex.Lock()
   122  	defer a.mutex.Unlock()
   123  
   124  	ent, ok := a.get(key)
   125  	if !ok {
   126  		return lo.Empty[V](), time.Time{}, false
   127  	}
   128  
   129  	return ent.value, time.Unix(ent.expires, 0), true
   130  }
   131  
   132  // Len determines the number of currently cached entries.
   133  // This method is side-effect free in the sense that it does not attempt to optimize random cache access.
   134  func (a *ARC[K, V]) Len() int {
   135  	a.mutex.Lock()
   136  	defer a.mutex.Unlock()
   137  
   138  	return a.len
   139  }
   140  
   141  func (a *ARC[K, V]) req(ent *entry[K, V]) {
   142  	switch {
   143  	case ent.ll == a.t1 || ent.ll == a.t2:
   144  		// Case I
   145  		ent.setMRU(a.t2)
   146  	case ent.ll == a.b1:
   147  		// Case II
   148  		// Cache Miss in t1 and t2
   149  
   150  		// Adaptation
   151  		var d int
   152  		if a.b1.Len() >= a.b2.Len() {
   153  			d = 1
   154  		} else {
   155  			d = a.b2.Len() / a.b1.Len()
   156  		}
   157  		a.p = min(a.p+d, a.c)
   158  
   159  		a.replace(ent)
   160  		ent.setMRU(a.t2)
   161  	case ent.ll == a.b2:
   162  		// Case III
   163  		// Cache Miss in t1 and t2
   164  
   165  		// Adaptation
   166  		var d int
   167  		if a.b2.Len() >= a.b1.Len() {
   168  			d = 1
   169  		} else {
   170  			d = a.b1.Len() / a.b2.Len()
   171  		}
   172  		a.p = max(a.p-d, 0)
   173  
   174  		a.replace(ent)
   175  		ent.setMRU(a.t2)
   176  	case ent.ll == nil && a.t1.Len()+a.b1.Len() == a.c:
   177  		// Case IV A
   178  		if a.t1.Len() < a.c {
   179  			a.delLRU(a.b1)
   180  			a.replace(ent)
   181  		} else {
   182  			a.delLRU(a.t1)
   183  		}
   184  		ent.setMRU(a.t1)
   185  	case ent.ll == nil && a.t1.Len()+a.b1.Len() < a.c:
   186  		// Case IV B
   187  		if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c {
   188  			if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c {
   189  				a.delLRU(a.b2)
   190  			}
   191  			a.replace(ent)
   192  		}
   193  		ent.setMRU(a.t1)
   194  	case ent.ll == nil:
   195  		// Case IV, not A nor B
   196  		ent.setMRU(a.t1)
   197  	}
   198  }
   199  
   200  func (a *ARC[K, V]) delLRU(list *list.List[*entry[K, V]]) {
   201  	lru := list.Back()
   202  	list.Remove(lru)
   203  	a.len--
   204  	delete(a.cache, lru.Value.key)
   205  }
   206  
   207  func (a *ARC[K, V]) replace(ent *entry[K, V]) {
   208  	if a.t1.Len() > 0 && ((a.t1.Len() > a.p) || (ent.ll == a.b2 && a.t1.Len() == a.p)) {
   209  		lru := a.t1.Back().Value
   210  		lru.value = lo.Empty[V]()
   211  		lru.ghost = true
   212  		a.len--
   213  		lru.setMRU(a.b1)
   214  	} else {
   215  		lru := a.t2.Back().Value
   216  		lru.value = lo.Empty[V]()
   217  		lru.ghost = true
   218  		a.len--
   219  		lru.setMRU(a.b2)
   220  	}
   221  }
   222  
   223  func min(a, b int) int {
   224  	if a < b {
   225  		return a
   226  	}
   227  	return b
   228  }
   229  
   230  func max(a int, b int) int {
   231  	if a < b {
   232  		return b
   233  	}
   234  	return a
   235  }