mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
feat(cache): implement TTLCache and TimeCache (#1822)
* feat(pkg): implement ttlcache and timecache
This commit is contained in:
parent
acef4ac624
commit
c1d8a4a850
8 changed files with 742 additions and 21 deletions
245
pkg/ttlcache/ttlcache_test.go
Normal file
245
pkg/ttlcache/ttlcache_test.go
Normal file
|
@ -0,0 +1,245 @@
|
|||
package ttlcache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(1 * time.Second))
|
||||
defer c.Close()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
val, ok := c.Get(i)
|
||||
if !ok {
|
||||
t.Fatalf("missing key: %d", i)
|
||||
} else if !val {
|
||||
t.Fatalf("bad value on key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpirations(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(200 * time.Millisecond))
|
||||
defer c.Close()
|
||||
for i := 0; i < 10; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, ok := c.Get(i); ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwaps(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(200 * time.Millisecond))
|
||||
defer c.Close()
|
||||
for i := 0; i < 10; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, ok := c.Get(i); ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 10; i < 20; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
if _, ok := c.Get(i); !ok {
|
||||
t.Fatalf("missing key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetimer(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(200 * time.Millisecond))
|
||||
defer c.Close()
|
||||
for i := 1; i < 10; i++ {
|
||||
c.Set(i, true, time.Duration(10-i)*100*time.Millisecond)
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
for i := 1; i < 10; i++ {
|
||||
if _, ok := c.Get(i); ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchedule(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(1 * time.Second))
|
||||
defer c.Close()
|
||||
for i := 1; i < 10; i++ {
|
||||
c.Set(i, true, time.Duration(i)*100*time.Millisecond)
|
||||
}
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
for i := 1; i < 10; i++ {
|
||||
if _, ok := c.Get(i); ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterlace(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(100 * time.Millisecond))
|
||||
defer c.Close()
|
||||
swap := false
|
||||
for i := 0; i < 10; i++ {
|
||||
swap = !swap
|
||||
ttl := DefaultTTL
|
||||
if swap {
|
||||
ttl = NoTTL
|
||||
}
|
||||
c.Set(i, true, ttl)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
swap = false
|
||||
for i := 0; i < 10; i++ {
|
||||
swap = !swap
|
||||
if !swap {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := c.Get(i); !ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReschedule(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(100 * time.Millisecond))
|
||||
defer c.Close()
|
||||
for i := 1; i < 10; i++ {
|
||||
c.Set(i, true, NoTTL)
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
for i := 1; i < 10; i++ {
|
||||
if _, ok := c.Get(i); ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRescheduleNoTTL(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(100 * time.Millisecond))
|
||||
defer c.Close()
|
||||
for i := 1; i < 10; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
c.Set(i, true, NoTTL)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
for i := 1; i < 10; i++ {
|
||||
if _, ok := c.Get(i); !ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := New[int, bool](Options[int, bool]{}.SetDefaultTTL(100 * time.Millisecond))
|
||||
defer c.Close()
|
||||
for i := 1; i < 10; i++ {
|
||||
c.Set(i, true, NoTTL)
|
||||
c.Delete(i)
|
||||
}
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
if _, ok := c.Get(i); ok {
|
||||
t.Fatalf("found key: %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeallocationTimeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
hit := false
|
||||
o := Options[int, bool]{}.
|
||||
SetDefaultTTL(time.Millisecond * 100).
|
||||
SetDeallocationFunc(func(key int, value bool, reason DeallocationReason) { hit = reason == ReasonTimedOut })
|
||||
|
||||
c := New[int, bool](o)
|
||||
defer c.Close()
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
if !hit {
|
||||
t.Fatalf("Deallocation not hit.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeallocationDeleted(t *testing.T) {
|
||||
t.Parallel()
|
||||
hit := false
|
||||
o := Options[int, bool]{}.
|
||||
SetDefaultTTL(time.Millisecond * 100).
|
||||
SetDeallocationFunc(func(key int, value bool, reason DeallocationReason) { hit = reason == ReasonDeleted })
|
||||
|
||||
c := New[int, bool](o)
|
||||
defer c.Close()
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
c.Delete(i)
|
||||
}
|
||||
|
||||
if !hit {
|
||||
t.Fatalf("Deallocation not hit.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimerReset(t *testing.T) {
|
||||
t.Parallel()
|
||||
ch := make(chan struct{})
|
||||
defer close(ch)
|
||||
|
||||
c := New[int, bool](Options[int, bool]{}.
|
||||
SetDefaultTTL(time.Millisecond * 100).
|
||||
SetDeallocationFunc(func(key int, value bool, reason DeallocationReason) { ch <- struct{}{} }))
|
||||
|
||||
defer c.Close()
|
||||
|
||||
const base = 0
|
||||
const rounds = 1
|
||||
for i := base; i < rounds; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
for i := base; i < rounds; i++ {
|
||||
<-ch
|
||||
}
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
c.Set(i, true, DefaultTTL)
|
||||
}
|
||||
|
||||
for i := base; i < rounds; i++ {
|
||||
<-ch
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue