2019-07-31 23:19:07 +02:00
|
|
|
// Package cache implements a simple cache where the entries are
|
|
|
|
// expired after a given time (5 minutes of disuse by default).
|
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
2020-11-30 12:46:06 +01:00
|
|
|
"strings"
|
2019-07-31 23:19:07 +02:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Cache holds values indexed by string, but expired after a given (5
|
|
|
|
// minutes by default).
|
|
|
|
type Cache struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
cache map[string]*cacheEntry
|
|
|
|
expireRunning bool
|
|
|
|
expireDuration time.Duration // expire the cache entry when it is older than this
|
|
|
|
expireInterval time.Duration // interval to run the cache expire
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
finalize func(value any)
|
2019-07-31 23:19:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new cache with the default expire duration and interval
|
|
|
|
func New() *Cache {
|
|
|
|
return &Cache{
|
|
|
|
cache: map[string]*cacheEntry{},
|
|
|
|
expireRunning: false,
|
|
|
|
expireDuration: 300 * time.Second,
|
|
|
|
expireInterval: 60 * time.Second,
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
finalize: func(_ any) {},
|
2019-07-31 23:19:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-29 18:18:49 +02:00
|
|
|
// SetExpireDuration sets the interval at which things expire
|
|
|
|
//
|
|
|
|
// If it is less than or equal to 0 then things are never cached
|
|
|
|
func (c *Cache) SetExpireDuration(d time.Duration) *Cache {
|
|
|
|
c.expireDuration = d
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns true if we aren't to cache anything
|
|
|
|
func (c *Cache) noCache() bool {
|
|
|
|
return c.expireDuration <= 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetExpireInterval sets the interval at which the cache expiry runs
|
|
|
|
//
|
|
|
|
// Set to 0 or a -ve number to disable
|
|
|
|
func (c *Cache) SetExpireInterval(d time.Duration) *Cache {
|
|
|
|
if d <= 0 {
|
|
|
|
d = 100 * 365 * 24 * time.Hour
|
|
|
|
}
|
|
|
|
c.expireInterval = d
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2019-07-31 23:19:07 +02:00
|
|
|
// cacheEntry is stored in the cache
|
|
|
|
type cacheEntry struct {
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
value any // cached item
|
|
|
|
err error // creation error
|
|
|
|
key string // key
|
|
|
|
lastUsed time.Time // time used for expiry
|
|
|
|
pinCount int // non zero if the entry should not be removed
|
2019-07-31 23:19:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateFunc is called to create new values. If the create function
|
|
|
|
// returns an error it will be cached if ok is true, otherwise the
|
|
|
|
// error will just be returned, allowing negative caching if required.
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
type CreateFunc func(key string) (value any, ok bool, error error)
|
2019-07-31 23:19:07 +02:00
|
|
|
|
|
|
|
// used marks an entry as accessed now and kicks the expire timer off
|
|
|
|
// should be called with the lock held
|
|
|
|
func (c *Cache) used(entry *cacheEntry) {
|
|
|
|
entry.lastUsed = time.Now()
|
|
|
|
if !c.expireRunning {
|
|
|
|
time.AfterFunc(c.expireInterval, c.cacheExpire)
|
|
|
|
c.expireRunning = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get gets a value named key either from the cache or creates it
|
|
|
|
// afresh with the create function.
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
func (c *Cache) Get(key string, create CreateFunc) (value any, err error) {
|
2019-07-31 23:19:07 +02:00
|
|
|
c.mu.Lock()
|
|
|
|
entry, ok := c.cache[key]
|
|
|
|
if !ok {
|
|
|
|
c.mu.Unlock() // Unlock in case Get is called recursively
|
|
|
|
value, ok, err = create(key)
|
|
|
|
if err != nil && !ok {
|
|
|
|
return value, err
|
|
|
|
}
|
|
|
|
entry = &cacheEntry{
|
|
|
|
value: value,
|
|
|
|
key: key,
|
|
|
|
err: err,
|
|
|
|
}
|
|
|
|
c.mu.Lock()
|
2021-03-29 18:18:49 +02:00
|
|
|
if !c.noCache() {
|
|
|
|
c.cache[key] = entry
|
|
|
|
}
|
2019-07-31 23:19:07 +02:00
|
|
|
}
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
c.used(entry)
|
|
|
|
return entry.value, entry.err
|
|
|
|
}
|
|
|
|
|
2020-05-01 13:19:19 +02:00
|
|
|
func (c *Cache) addPin(key string, count int) {
|
|
|
|
c.mu.Lock()
|
|
|
|
entry, ok := c.cache[key]
|
|
|
|
if ok {
|
|
|
|
entry.pinCount += count
|
|
|
|
c.used(entry)
|
|
|
|
}
|
|
|
|
c.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pin a value in the cache if it exists
|
|
|
|
func (c *Cache) Pin(key string) {
|
|
|
|
c.addPin(key, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unpin a value in the cache if it exists
|
|
|
|
func (c *Cache) Unpin(key string) {
|
|
|
|
c.addPin(key, -1)
|
|
|
|
}
|
|
|
|
|
2024-01-19 11:33:24 +01:00
|
|
|
// PutErr puts a value named key with err into the cache
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
func (c *Cache) PutErr(key string, value any, err error) {
|
2019-07-31 23:19:07 +02:00
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
2021-03-29 18:18:49 +02:00
|
|
|
if c.noCache() {
|
|
|
|
return
|
|
|
|
}
|
2019-07-31 23:19:07 +02:00
|
|
|
entry := &cacheEntry{
|
|
|
|
value: value,
|
|
|
|
key: key,
|
2024-01-19 11:33:24 +01:00
|
|
|
err: err,
|
2019-07-31 23:19:07 +02:00
|
|
|
}
|
|
|
|
c.used(entry)
|
|
|
|
c.cache[key] = entry
|
|
|
|
}
|
|
|
|
|
2024-01-19 11:33:24 +01:00
|
|
|
// Put puts a value named key into the cache
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
func (c *Cache) Put(key string, value any) {
|
2024-01-19 11:33:24 +01:00
|
|
|
c.PutErr(key, value, nil)
|
|
|
|
}
|
|
|
|
|
2019-07-31 23:19:07 +02:00
|
|
|
// GetMaybe returns the key and true if found, nil and false if not
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
func (c *Cache) GetMaybe(key string) (value any, found bool) {
|
2019-07-31 23:19:07 +02:00
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
entry, found := c.cache[key]
|
|
|
|
if !found {
|
|
|
|
return nil, found
|
|
|
|
}
|
|
|
|
c.used(entry)
|
|
|
|
return entry.value, found
|
|
|
|
}
|
|
|
|
|
2020-11-30 12:46:06 +01:00
|
|
|
// Delete the entry passed in
|
|
|
|
//
|
|
|
|
// Returns true if the entry was found
|
|
|
|
func (c *Cache) Delete(key string) bool {
|
|
|
|
c.mu.Lock()
|
2022-06-28 13:51:59 +02:00
|
|
|
entry, found := c.cache[key]
|
|
|
|
if found {
|
|
|
|
c.finalize(entry.value)
|
|
|
|
}
|
2020-11-30 12:46:06 +01:00
|
|
|
delete(c.cache, key)
|
|
|
|
c.mu.Unlock()
|
|
|
|
return found
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeletePrefix deletes all entries with the given prefix
|
|
|
|
//
|
|
|
|
// Returns number of entries deleted
|
|
|
|
func (c *Cache) DeletePrefix(prefix string) (deleted int) {
|
|
|
|
c.mu.Lock()
|
2022-06-28 13:51:59 +02:00
|
|
|
for key, entry := range c.cache {
|
|
|
|
if !strings.HasPrefix(key, prefix) {
|
|
|
|
continue
|
2020-11-30 12:46:06 +01:00
|
|
|
}
|
2022-06-28 13:51:59 +02:00
|
|
|
c.finalize(entry.value)
|
|
|
|
delete(c.cache, key)
|
|
|
|
deleted++
|
2020-11-30 12:46:06 +01:00
|
|
|
}
|
|
|
|
c.mu.Unlock()
|
|
|
|
return deleted
|
|
|
|
}
|
|
|
|
|
2020-05-01 13:19:19 +02:00
|
|
|
// Rename renames the item at oldKey to newKey.
|
|
|
|
//
|
|
|
|
// If there was an existing item at newKey then it takes precedence
|
|
|
|
// and is returned otherwise the item (if any) at oldKey is returned.
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
func (c *Cache) Rename(oldKey, newKey string) (value any, found bool) {
|
2020-05-01 13:19:19 +02:00
|
|
|
c.mu.Lock()
|
|
|
|
if newEntry, newFound := c.cache[newKey]; newFound {
|
|
|
|
// If new entry is found use that
|
2022-11-08 12:44:03 +01:00
|
|
|
if oldEntry, oldFound := c.cache[oldKey]; oldFound {
|
|
|
|
// If there's an old entry that is different we must finalize it
|
|
|
|
if newEntry.value != oldEntry.value {
|
|
|
|
c.finalize(c.cache[oldKey].value)
|
|
|
|
}
|
2022-06-28 13:51:59 +02:00
|
|
|
}
|
2020-05-01 13:19:19 +02:00
|
|
|
delete(c.cache, oldKey)
|
|
|
|
value, found = newEntry.value, newFound
|
|
|
|
c.used(newEntry)
|
|
|
|
} else if oldEntry, oldFound := c.cache[oldKey]; oldFound {
|
|
|
|
// If old entry is found rename it to new and use that
|
|
|
|
c.cache[newKey] = oldEntry
|
2022-06-28 13:51:59 +02:00
|
|
|
// No need to shutdown here, as value lives on under newKey
|
2020-05-01 13:19:19 +02:00
|
|
|
delete(c.cache, oldKey)
|
|
|
|
c.used(oldEntry)
|
|
|
|
value, found = oldEntry.value, oldFound
|
|
|
|
}
|
|
|
|
c.mu.Unlock()
|
|
|
|
return value, found
|
|
|
|
}
|
|
|
|
|
2019-07-31 23:19:07 +02:00
|
|
|
// cacheExpire expires any entries that haven't been used recently
|
|
|
|
func (c *Cache) cacheExpire() {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
now := time.Now()
|
|
|
|
for key, entry := range c.cache {
|
2020-05-01 13:19:19 +02:00
|
|
|
if entry.pinCount <= 0 && now.Sub(entry.lastUsed) > c.expireDuration {
|
2022-06-28 13:51:59 +02:00
|
|
|
c.finalize(entry.value)
|
2019-07-31 23:19:07 +02:00
|
|
|
delete(c.cache, key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(c.cache) != 0 {
|
|
|
|
time.AfterFunc(c.expireInterval, c.cacheExpire)
|
|
|
|
c.expireRunning = true
|
|
|
|
} else {
|
|
|
|
c.expireRunning = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-20 12:39:20 +02:00
|
|
|
// Clear removes everything from the cache
|
2019-07-31 23:19:07 +02:00
|
|
|
func (c *Cache) Clear() {
|
|
|
|
c.mu.Lock()
|
2022-06-28 13:51:59 +02:00
|
|
|
for key, entry := range c.cache {
|
|
|
|
c.finalize(entry.value)
|
|
|
|
delete(c.cache, key)
|
2019-07-31 23:19:07 +02:00
|
|
|
}
|
|
|
|
c.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Entries returns the number of entries in the cache
|
|
|
|
func (c *Cache) Entries() int {
|
|
|
|
c.mu.Lock()
|
|
|
|
entries := len(c.cache)
|
|
|
|
c.mu.Unlock()
|
|
|
|
return entries
|
|
|
|
}
|
2022-06-28 13:51:59 +02:00
|
|
|
|
|
|
|
// SetFinalizer sets a function to be called when a value drops out of the cache
|
build: modernize Go usage
This commit modernizes Go usage. This was done with:
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
Then files needed to be `go fmt`ed and a few comments needed to be
restored.
The modernizations include replacing
- if/else conditional assignment by a call to the built-in min or max functions added in go1.21
- sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21
- interface{} by the 'any' type added in go1.18
- append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21
- loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21
- []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19
- append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21
- a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
2025-02-26 22:08:12 +01:00
|
|
|
func (c *Cache) SetFinalizer(finalize func(any)) {
|
2022-06-28 13:51:59 +02:00
|
|
|
c.mu.Lock()
|
|
|
|
c.finalize = finalize
|
|
|
|
c.mu.Unlock()
|
|
|
|
}
|
2024-03-10 05:36:57 +01:00
|
|
|
|
|
|
|
// EntriesWithPinCount returns the number of pinned and unpinned entries in the cache
|
|
|
|
//
|
|
|
|
// Each entry is counted only once, regardless of entry.pinCount
|
|
|
|
func (c *Cache) EntriesWithPinCount() (pinned, unpinned int) {
|
|
|
|
c.mu.Lock()
|
|
|
|
for _, entry := range c.cache {
|
|
|
|
if entry.pinCount <= 0 {
|
|
|
|
unpinned++
|
|
|
|
} else {
|
|
|
|
pinned++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c.mu.Unlock()
|
|
|
|
return pinned, unpinned
|
|
|
|
}
|