[performance] update go-cache library (#1917)
* update go-cache library Signed-off-by: kim <grufwub@gmail.com> * fix broken test after cache library upgrade Signed-off-by: kim <grufwub@gmail.com> * fix the webfinger test Signed-off-by: kim <grufwub@gmail.com> --------- Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
831ae09f8b
commit
8e0043104d
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.20
|
||||||
require (
|
require (
|
||||||
codeberg.org/gruf/go-bytesize v1.0.2
|
codeberg.org/gruf/go-bytesize v1.0.2
|
||||||
codeberg.org/gruf/go-byteutil v1.1.2
|
codeberg.org/gruf/go-byteutil v1.1.2
|
||||||
codeberg.org/gruf/go-cache/v3 v3.3.3
|
codeberg.org/gruf/go-cache/v3 v3.4.1
|
||||||
codeberg.org/gruf/go-debug v1.3.0
|
codeberg.org/gruf/go-debug v1.3.0
|
||||||
codeberg.org/gruf/go-errors/v2 v2.2.0
|
codeberg.org/gruf/go-errors/v2 v2.2.0
|
||||||
codeberg.org/gruf/go-fastcopy v1.1.2
|
codeberg.org/gruf/go-fastcopy v1.1.2
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -48,8 +48,8 @@ codeberg.org/gruf/go-bytesize v1.0.2/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacp
|
||||||
codeberg.org/gruf/go-byteutil v1.0.0/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
|
codeberg.org/gruf/go-byteutil v1.0.0/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
|
||||||
codeberg.org/gruf/go-byteutil v1.1.2 h1:TQLZtTxTNca9xEfDIndmo7nBYxeS94nrv/9DS3Nk5Tw=
|
codeberg.org/gruf/go-byteutil v1.1.2 h1:TQLZtTxTNca9xEfDIndmo7nBYxeS94nrv/9DS3Nk5Tw=
|
||||||
codeberg.org/gruf/go-byteutil v1.1.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
|
codeberg.org/gruf/go-byteutil v1.1.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
|
||||||
codeberg.org/gruf/go-cache/v3 v3.3.3 h1:CzOFg6JV+typ8Jst1rrYDbZjxEV7bUxKggkbfN5Y79o=
|
codeberg.org/gruf/go-cache/v3 v3.4.1 h1:dejl5nJC7wEsmbcU8D4EgZlo/tZgVO6iwPdrLBAa7eQ=
|
||||||
codeberg.org/gruf/go-cache/v3 v3.3.3/go.mod h1:pTeVPEb9DshXUkd8Dg76UcsLpU6EC/tXQ2qb+JrmxEc=
|
codeberg.org/gruf/go-cache/v3 v3.4.1/go.mod h1:pTeVPEb9DshXUkd8Dg76UcsLpU6EC/tXQ2qb+JrmxEc=
|
||||||
codeberg.org/gruf/go-debug v1.3.0 h1:PIRxQiWUFKtGOGZFdZ3Y0pqyfI0Xr87j224IYe2snZs=
|
codeberg.org/gruf/go-debug v1.3.0 h1:PIRxQiWUFKtGOGZFdZ3Y0pqyfI0Xr87j224IYe2snZs=
|
||||||
codeberg.org/gruf/go-debug v1.3.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
codeberg.org/gruf/go-debug v1.3.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
||||||
codeberg.org/gruf/go-errors/v2 v2.0.0/go.mod h1:ZRhbdhvgoUA3Yw6e56kd9Ox984RrvbEFC2pOXyHDJP4=
|
codeberg.org/gruf/go-errors/v2 v2.0.0/go.mod h1:ZRhbdhvgoUA3Yw6e56kd9Ox984RrvbEFC2pOXyHDJP4=
|
||||||
|
|
|
@ -87,11 +87,9 @@ func (suite *FingerTestSuite) TestFingerWithHostMetaCacheStrategy() {
|
||||||
|
|
||||||
// the TTL of the entry should have extended because we did a second
|
// the TTL of the entry should have extended because we did a second
|
||||||
// successful finger
|
// successful finger
|
||||||
if repeatTime.Equal(initialTime) {
|
if repeatTime == initialTime {
|
||||||
suite.FailNowf("expected webfinger cache entry to have different expiry times", "initial: '%s', repeat: '%s'", initialTime, repeatTime)
|
suite.FailNowf("expected webfinger cache entry to have different expiry times", "initial: '%s', repeat: '%s'", initialTime, repeatTime)
|
||||||
}
|
} else if repeatTime < initialTime {
|
||||||
|
|
||||||
if repeatTime.Before(initialTime) {
|
|
||||||
suite.FailNowf("expected webfinger cache entry to not be a time traveller", "initial: '%s', repeat: '%s'", initialTime, repeatTime)
|
suite.FailNowf("expected webfinger cache entry to not be a time traveller", "initial: '%s', repeat: '%s'", initialTime, repeatTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
"codeberg.org/gruf/go-cache/v3/ttl"
|
"codeberg.org/gruf/go-cache/v3/ttl"
|
||||||
"codeberg.org/gruf/go-errors/v2"
|
"codeberg.org/gruf/go-errors/v2"
|
||||||
|
@ -385,7 +386,7 @@ func (c *Cache[Value]) store(res result[Value]) (evict func()) {
|
||||||
|
|
||||||
// Store main entry under primary key, using evict hook if needed
|
// Store main entry under primary key, using evict hook if needed
|
||||||
c.cache.Cache.SetWithHook(pnext, &ttl.Entry[int64, result[Value]]{
|
c.cache.Cache.SetWithHook(pnext, &ttl.Entry[int64, result[Value]]{
|
||||||
Expiry: time.Now().Add(c.cache.TTL),
|
Expiry: c.expiry(),
|
||||||
Key: pnext,
|
Key: pnext,
|
||||||
Value: res,
|
Value: res,
|
||||||
}, func(_ int64, item *ttl.Entry[int64, result[Value]]) {
|
}, func(_ int64, item *ttl.Entry[int64, result[Value]]) {
|
||||||
|
@ -395,6 +396,19 @@ func (c *Cache[Value]) store(res result[Value]) (evict func()) {
|
||||||
return evict
|
return evict
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname runtime_nanotime runtime.nanotime
|
||||||
|
func runtime_nanotime() uint64
|
||||||
|
|
||||||
|
// expiry returns an the next expiry time to use for an entry,
|
||||||
|
// which is equivalent to time.Now().Add(ttl), or zero if disabled.
|
||||||
|
func (c *Cache[Value]) expiry() uint64 {
|
||||||
|
if ttl := c.cache.TTL; ttl > 0 {
|
||||||
|
return runtime_nanotime() +
|
||||||
|
uint64(c.cache.TTL)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type result[Value any] struct {
|
type result[Value any] struct {
|
||||||
// keys accessible under
|
// keys accessible under
|
||||||
Keys cacheKeys
|
Keys cacheKeys
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ttl
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
"codeberg.org/gruf/go-maps"
|
"codeberg.org/gruf/go-maps"
|
||||||
)
|
)
|
||||||
|
@ -11,7 +12,7 @@ import (
|
||||||
type Entry[Key comparable, Value any] struct {
|
type Entry[Key comparable, Value any] struct {
|
||||||
Key Key
|
Key Key
|
||||||
Value Value
|
Value Value
|
||||||
Expiry time.Time
|
Expiry uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache is the underlying Cache implementation, providing both the base Cache interface and unsafe access to underlying map to allow flexibility in building your own.
|
// Cache is the underlying Cache implementation, providing both the base Cache interface and unsafe access to underlying map to allow flexibility in building your own.
|
||||||
|
@ -67,7 +68,7 @@ func (c *Cache[K, V]) Start(freq time.Duration) (ok bool) {
|
||||||
// Safely start
|
// Safely start
|
||||||
c.Lock()
|
c.Lock()
|
||||||
|
|
||||||
if ok = c.stop == nil; ok {
|
if ok = (c.stop == nil); ok {
|
||||||
// Not yet running, schedule us
|
// Not yet running, schedule us
|
||||||
c.stop = schedule(c.Sweep, freq)
|
c.stop = schedule(c.Sweep, freq)
|
||||||
}
|
}
|
||||||
|
@ -83,7 +84,7 @@ func (c *Cache[K, V]) Stop() (ok bool) {
|
||||||
// Safely stop
|
// Safely stop
|
||||||
c.Lock()
|
c.Lock()
|
||||||
|
|
||||||
if ok = c.stop != nil; ok {
|
if ok = (c.stop != nil); ok {
|
||||||
// We're running, cancel evicts
|
// We're running, cancel evicts
|
||||||
c.stop()
|
c.stop()
|
||||||
c.stop = nil
|
c.stop = nil
|
||||||
|
@ -96,23 +97,32 @@ func (c *Cache[K, V]) Stop() (ok bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sweep attempts to evict expired items (with callback!) from cache.
|
// Sweep attempts to evict expired items (with callback!) from cache.
|
||||||
func (c *Cache[K, V]) Sweep(now time.Time) {
|
func (c *Cache[K, V]) Sweep(_ time.Time) {
|
||||||
var (
|
var (
|
||||||
// evicted key-values.
|
// evicted key-values.
|
||||||
kvs []kv[K, V]
|
kvs []kv[K, V]
|
||||||
|
|
||||||
// hook func ptrs.
|
// hook func ptrs.
|
||||||
evict func(K, V)
|
evict func(K, V)
|
||||||
|
|
||||||
|
// get current nanoseconds.
|
||||||
|
now = runtime_nanotime()
|
||||||
)
|
)
|
||||||
|
|
||||||
c.locked(func() {
|
c.locked(func() {
|
||||||
|
if c.TTL <= 0 {
|
||||||
|
// sweep is
|
||||||
|
// disabled
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Sentinel value
|
// Sentinel value
|
||||||
after := -1
|
after := -1
|
||||||
|
|
||||||
// The cache will be ordered by expiry date, we iterate until we reach the index of
|
// The cache will be ordered by expiry date, we iterate until we reach the index of
|
||||||
// the youngest item that hsa expired, as all succeeding items will also be expired.
|
// the youngest item that hsa expired, as all succeeding items will also be expired.
|
||||||
c.Cache.RangeIf(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) bool {
|
c.Cache.RangeIf(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) bool {
|
||||||
if now.After(item.Expiry) {
|
if now > item.Expiry {
|
||||||
after = i
|
after = i
|
||||||
|
|
||||||
// evict all older items
|
// evict all older items
|
||||||
|
@ -161,10 +171,6 @@ func (c *Cache[K, V]) SetInvalidateCallback(hook func(K, V)) {
|
||||||
|
|
||||||
// SetTTL: implements cache.Cache's SetTTL().
|
// SetTTL: implements cache.Cache's SetTTL().
|
||||||
func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) {
|
func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) {
|
||||||
if ttl < 0 {
|
|
||||||
panic("ttl must be greater than zero")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.locked(func() {
|
c.locked(func() {
|
||||||
// Set updated TTL
|
// Set updated TTL
|
||||||
diff := ttl - c.TTL
|
diff := ttl - c.TTL
|
||||||
|
@ -173,7 +179,7 @@ func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) {
|
||||||
if update {
|
if update {
|
||||||
// Update existing cache entries with new expiry time
|
// Update existing cache entries with new expiry time
|
||||||
c.Cache.Range(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) {
|
c.Cache.Range(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) {
|
||||||
item.Expiry = item.Expiry.Add(diff)
|
item.Expiry += uint64(diff)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -198,8 +204,8 @@ func (c *Cache[K, V]) Get(key K) (V, bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update fetched item's expiry
|
// Update fetched's expiry
|
||||||
item.Expiry = time.Now().Add(c.TTL)
|
item.Expiry = c.expiry()
|
||||||
|
|
||||||
// Set value.
|
// Set value.
|
||||||
v = item.Value
|
v = item.Value
|
||||||
|
@ -234,7 +240,7 @@ func (c *Cache[K, V]) Add(key K, value V) bool {
|
||||||
|
|
||||||
// Alloc new entry.
|
// Alloc new entry.
|
||||||
new := c.alloc()
|
new := c.alloc()
|
||||||
new.Expiry = time.Now().Add(c.TTL)
|
new.Expiry = c.expiry()
|
||||||
new.Key = key
|
new.Key = key
|
||||||
new.Value = value
|
new.Value = value
|
||||||
|
|
||||||
|
@ -290,12 +296,12 @@ func (c *Cache[K, V]) Set(key K, value V) {
|
||||||
oldV = item.Value
|
oldV = item.Value
|
||||||
|
|
||||||
// Update the existing item.
|
// Update the existing item.
|
||||||
item.Expiry = time.Now().Add(c.TTL)
|
item.Expiry = c.expiry()
|
||||||
item.Value = value
|
item.Value = value
|
||||||
} else {
|
} else {
|
||||||
// Alloc new entry.
|
// Alloc new entry.
|
||||||
new := c.alloc()
|
new := c.alloc()
|
||||||
new.Expiry = time.Now().Add(c.TTL)
|
new.Expiry = c.expiry()
|
||||||
new.Key = key
|
new.Key = key
|
||||||
new.Value = value
|
new.Value = value
|
||||||
|
|
||||||
|
@ -355,7 +361,7 @@ func (c *Cache[K, V]) CAS(key K, old V, new V, cmp func(V, V) bool) bool {
|
||||||
oldV = item.Value
|
oldV = item.Value
|
||||||
|
|
||||||
// Update value + expiry.
|
// Update value + expiry.
|
||||||
item.Expiry = time.Now().Add(c.TTL)
|
item.Expiry = c.expiry()
|
||||||
item.Value = new
|
item.Value = new
|
||||||
|
|
||||||
// Set hook func ptr.
|
// Set hook func ptr.
|
||||||
|
@ -396,7 +402,7 @@ func (c *Cache[K, V]) Swap(key K, swp V) V {
|
||||||
oldV = item.Value
|
oldV = item.Value
|
||||||
|
|
||||||
// Update value + expiry.
|
// Update value + expiry.
|
||||||
item.Expiry = time.Now().Add(c.TTL)
|
item.Expiry = c.expiry()
|
||||||
item.Value = swp
|
item.Value = swp
|
||||||
|
|
||||||
// Set hook func ptr.
|
// Set hook func ptr.
|
||||||
|
@ -603,14 +609,26 @@ func (c *Cache[K, V]) free(e *Entry[K, V]) {
|
||||||
var (
|
var (
|
||||||
zk K
|
zk K
|
||||||
zv V
|
zv V
|
||||||
zt time.Time
|
|
||||||
)
|
)
|
||||||
e.Expiry = zt
|
e.Expiry = 0
|
||||||
e.Key = zk
|
e.Key = zk
|
||||||
e.Value = zv
|
e.Value = zv
|
||||||
c.pool = append(c.pool, e)
|
c.pool = append(c.pool, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname runtime_nanotime runtime.nanotime
|
||||||
|
func runtime_nanotime() uint64
|
||||||
|
|
||||||
|
// expiry returns an the next expiry time to use for an entry,
|
||||||
|
// which is equivalent to time.Now().Add(ttl), or zero if disabled.
|
||||||
|
func (c *Cache[K, V]) expiry() uint64 {
|
||||||
|
if ttl := c.TTL; ttl > 0 {
|
||||||
|
return runtime_nanotime() +
|
||||||
|
uint64(c.TTL)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type kv[K comparable, V any] struct {
|
type kv[K comparable, V any] struct {
|
||||||
K K
|
K K
|
||||||
V V
|
V V
|
||||||
|
|
|
@ -13,7 +13,7 @@ codeberg.org/gruf/go-bytesize
|
||||||
# codeberg.org/gruf/go-byteutil v1.1.2
|
# codeberg.org/gruf/go-byteutil v1.1.2
|
||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
codeberg.org/gruf/go-byteutil
|
codeberg.org/gruf/go-byteutil
|
||||||
# codeberg.org/gruf/go-cache/v3 v3.3.3
|
# codeberg.org/gruf/go-cache/v3 v3.4.1
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
codeberg.org/gruf/go-cache/v3
|
codeberg.org/gruf/go-cache/v3
|
||||||
codeberg.org/gruf/go-cache/v3/result
|
codeberg.org/gruf/go-cache/v3/result
|
||||||
|
|
Loading…
Reference in New Issue