@ -22,6 +22,8 @@ import (
"sync/atomic"
"testing"
"time"
"github.com/openimsdk/open-im-server/v3/pkg/localcache/lru"
)
func TestName ( t * testing . T ) {
@ -91,3 +93,68 @@ func TestName(t *testing.T) {
t . Log ( "del" , del . Load ( ) )
// 137.35s
}
// Test deadlock scenario when eviction callback deletes a linked key that hashes to the same slot.
func TestCacheEvictDeadlock ( t * testing . T ) {
ctx := context . Background ( )
c := New [ string ] ( WithLocalSlotNum ( 1 ) , WithLocalSlotSize ( 1 ) , WithLazy ( ) )
if _ , err := c . GetLink ( ctx , "k1" , func ( ctx context . Context ) ( string , error ) {
return "v1" , nil
} , "k2" ) ; err != nil {
t . Fatalf ( "seed cache failed: %v" , err )
}
done := make ( chan struct { } )
go func ( ) {
defer close ( done )
_ , _ = c . GetLink ( ctx , "k2" , func ( ctx context . Context ) ( string , error ) {
return "v2" , nil
} , "k1" )
} ( )
select {
case <- done :
// expected to finish quickly; current implementation deadlocks here.
case <- time . After ( time . Second ) :
t . Fatal ( "GetLink deadlocked during eviction of linked key" )
}
}
func TestExpirationLRUGetBatch ( t * testing . T ) {
l := lru . NewExpirationLRU [ string , string ] ( 2 , time . Minute , time . Second * 5 , EmptyTarget { } , nil )
keys := [ ] string { "a" , "b" }
values , err := l . GetBatch ( keys , func ( keys [ ] string ) ( map [ string ] string , error ) {
res := make ( map [ string ] string )
for _ , k := range keys {
res [ k ] = k + "_v"
}
return res , nil
} )
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
if len ( values ) != len ( keys ) {
t . Fatalf ( "expected %d values, got %d" , len ( keys ) , len ( values ) )
}
for _ , k := range keys {
if v , ok := values [ k ] ; ! ok || v != k + "_v" {
t . Fatalf ( "unexpected value for %s: %q, ok=%v" , k , v , ok )
}
}
// second batch should hit cache
values , err = l . GetBatch ( keys , func ( keys [ ] string ) ( map [ string ] string , error ) {
t . Fatalf ( "should not fetch on cache hit" )
return nil , nil
} )
if err != nil {
t . Fatalf ( "unexpected error on cache hit: %v" , err )
}
for _ , k := range keys {
if v , ok := values [ k ] ; ! ok || v != k + "_v" {
t . Fatalf ( "unexpected cached value for %s: %q, ok=%v" , k , v , ok )
}
}
}