diff --git a/go.mod b/go.mod index 990d54d49..4645df23e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( codeberg.org/gruf/go-bytesize v1.0.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-errors/v2 v2.2.0 codeberg.org/gruf/go-fastcopy v1.1.2 diff --git a/go.sum b/go.sum index 6cf9c6442..fd7db74c0 100644 --- a/go.sum +++ b/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.1.2 h1:TQLZtTxTNca9xEfDIndmo7nBYxeS94nrv/9DS3Nk5Tw= 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.3.3/go.mod h1:pTeVPEb9DshXUkd8Dg76UcsLpU6EC/tXQ2qb+JrmxEc= +codeberg.org/gruf/go-cache/v3 v3.4.1 h1:dejl5nJC7wEsmbcU8D4EgZlo/tZgVO6iwPdrLBAa7eQ= +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/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg= codeberg.org/gruf/go-errors/v2 v2.0.0/go.mod h1:ZRhbdhvgoUA3Yw6e56kd9Ox984RrvbEFC2pOXyHDJP4= diff --git a/internal/transport/finger_test.go b/internal/transport/finger_test.go index bd1e8b24d..e6814ac84 100644 --- a/internal/transport/finger_test.go +++ b/internal/transport/finger_test.go @@ -87,11 +87,9 @@ func (suite *FingerTestSuite) TestFingerWithHostMetaCacheStrategy() { // the TTL of the entry should have extended because we did a second // 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) - } - - if repeatTime.Before(initialTime) { + } else if repeatTime < initialTime { suite.FailNowf("expected webfinger cache entry to not be a time traveller", "initial: '%s', repeat: '%s'", initialTime, repeatTime) } diff --git a/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go b/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go index 5b16712b6..74644b073 100644 --- a/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go +++ b/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go @@ -4,6 +4,7 @@ import ( "context" "reflect" "time" + _ "unsafe" "codeberg.org/gruf/go-cache/v3/ttl" "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 c.cache.Cache.SetWithHook(pnext, &ttl.Entry[int64, result[Value]]{ - Expiry: time.Now().Add(c.cache.TTL), + Expiry: c.expiry(), Key: pnext, Value: res, }, func(_ int64, item *ttl.Entry[int64, result[Value]]) { @@ -395,6 +396,19 @@ func (c *Cache[Value]) store(res result[Value]) (evict func()) { 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 { // keys accessible under Keys cacheKeys diff --git a/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go b/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go index a5d9d6fc3..623a19910 100644 --- a/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go +++ b/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go @@ -3,6 +3,7 @@ package ttl import ( "sync" "time" + _ "unsafe" "codeberg.org/gruf/go-maps" ) @@ -11,7 +12,7 @@ import ( type Entry[Key comparable, Value any] struct { Key Key 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. @@ -67,7 +68,7 @@ func (c *Cache[K, V]) Start(freq time.Duration) (ok bool) { // Safely start c.Lock() - if ok = c.stop == nil; ok { + if ok = (c.stop == nil); ok { // Not yet running, schedule us c.stop = schedule(c.Sweep, freq) } @@ -83,7 +84,7 @@ func (c *Cache[K, V]) Stop() (ok bool) { // Safely stop c.Lock() - if ok = c.stop != nil; ok { + if ok = (c.stop != nil); ok { // We're running, cancel evicts c.stop() 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. -func (c *Cache[K, V]) Sweep(now time.Time) { +func (c *Cache[K, V]) Sweep(_ time.Time) { var ( // evicted key-values. kvs []kv[K, V] // hook func ptrs. evict func(K, V) + + // get current nanoseconds. + now = runtime_nanotime() ) c.locked(func() { + if c.TTL <= 0 { + // sweep is + // disabled + return + } + // Sentinel value after := -1 // 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. 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 // evict all older items @@ -161,10 +171,6 @@ func (c *Cache[K, V]) SetInvalidateCallback(hook func(K, V)) { // SetTTL: implements cache.Cache's SetTTL(). func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) { - if ttl < 0 { - panic("ttl must be greater than zero") - } - c.locked(func() { // Set updated TTL diff := ttl - c.TTL @@ -173,7 +179,7 @@ func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) { if update { // Update existing cache entries with new expiry time 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 } - // Update fetched item's expiry - item.Expiry = time.Now().Add(c.TTL) + // Update fetched's expiry + item.Expiry = c.expiry() // Set value. v = item.Value @@ -234,7 +240,7 @@ func (c *Cache[K, V]) Add(key K, value V) bool { // Alloc new entry. new := c.alloc() - new.Expiry = time.Now().Add(c.TTL) + new.Expiry = c.expiry() new.Key = key new.Value = value @@ -290,12 +296,12 @@ func (c *Cache[K, V]) Set(key K, value V) { oldV = item.Value // Update the existing item. - item.Expiry = time.Now().Add(c.TTL) + item.Expiry = c.expiry() item.Value = value } else { // Alloc new entry. new := c.alloc() - new.Expiry = time.Now().Add(c.TTL) + new.Expiry = c.expiry() new.Key = key 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 // Update value + expiry. - item.Expiry = time.Now().Add(c.TTL) + item.Expiry = c.expiry() item.Value = new // Set hook func ptr. @@ -396,7 +402,7 @@ func (c *Cache[K, V]) Swap(key K, swp V) V { oldV = item.Value // Update value + expiry. - item.Expiry = time.Now().Add(c.TTL) + item.Expiry = c.expiry() item.Value = swp // Set hook func ptr. @@ -603,14 +609,26 @@ func (c *Cache[K, V]) free(e *Entry[K, V]) { var ( zk K zv V - zt time.Time ) - e.Expiry = zt + e.Expiry = 0 e.Key = zk e.Value = zv 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 { K K V V diff --git a/vendor/modules.txt b/vendor/modules.txt index 43bb62829..d7c2a8879 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -13,7 +13,7 @@ codeberg.org/gruf/go-bytesize # codeberg.org/gruf/go-byteutil v1.1.2 ## explicit; go 1.16 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 codeberg.org/gruf/go-cache/v3 codeberg.org/gruf/go-cache/v3/result