From c51b3e3fe25f9fd03ed3ac4d07778f7cbecd1e8a Mon Sep 17 00:00:00 2001 From: Paul Wells Date: Tue, 23 Apr 2024 02:20:54 -0700 Subject: [PATCH] use ttlcache (#2677) * use ttlcache * go * test --- go.mod | 1 + go.sum | 2 + pkg/service/roommanager.go | 2 +- pkg/utils/ice_config_cache.go | 85 -------------------------------- pkg/utils/iceconfigcache.go | 42 ++++++++++++++++ pkg/utils/iceconfigcache_test.go | 18 +++++++ 6 files changed, 64 insertions(+), 86 deletions(-) delete mode 100644 pkg/utils/ice_config_cache.go create mode 100644 pkg/utils/iceconfigcache.go create mode 100644 pkg/utils/iceconfigcache_test.go diff --git a/go.mod b/go.mod index ce5f488e1..7b117582b 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/jellydator/ttlcache/v3 v3.2.0 github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 github.com/livekit/mediatransportutil v0.0.0-20240416023643-881d3dc5423e diff --git a/go.sum b/go.sum index f571264f5..d5c92f6fe 100644 --- a/go.sum +++ b/go.sum @@ -85,6 +85,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= +github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 3aafad3fd..3dfa146d5 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -504,7 +504,7 @@ func (r *RoomManager) StartSession( } }) participant.OnICEConfigChanged(func(participant types.LocalParticipant, iceConfig *livekit.ICEConfig) { - r.iceConfigCache.Put(iceConfigCacheKey{roomName, participant.Identity()}, iceConfig, time.Now()) + r.iceConfigCache.Put(iceConfigCacheKey{roomName, participant.Identity()}, iceConfig) }) go r.rtcSessionWorker(room, participant, requestSource) diff --git a/pkg/utils/ice_config_cache.go b/pkg/utils/ice_config_cache.go deleted file mode 100644 index a3ff2a22a..000000000 --- a/pkg/utils/ice_config_cache.go +++ /dev/null @@ -1,85 +0,0 @@ -package utils - -import ( - "sync" - "time" - - "github.com/livekit/protocol/livekit" - "go.uber.org/atomic" -) - -const ( - iceConfigTTLMin = 5 * time.Minute -) - -type iceConfigCacheEntry struct { - iceConfig *livekit.ICEConfig - modifiedAt time.Time -} - -type IceConfigCache[T comparable] struct { - lock sync.Mutex - ttl time.Duration - entries map[T]*iceConfigCacheEntry - - stopped atomic.Bool -} - -func NewIceConfigCache[T comparable](ttl time.Duration) *IceConfigCache[T] { - icc := &IceConfigCache[T]{ - entries: make(map[T]*iceConfigCacheEntry), - } - - if ttl < iceConfigTTLMin { - icc.ttl = iceConfigTTLMin - } else { - icc.ttl = ttl - } - - go icc.pruneWorker() - return icc -} - -func (icc *IceConfigCache[T]) Stop() { - icc.stopped.Store(true) -} - -func (icc *IceConfigCache[T]) Put(key T, iceConfig *livekit.ICEConfig, at time.Time) { - icc.lock.Lock() - defer icc.lock.Unlock() - - icc.entries[key] = &iceConfigCacheEntry{ - iceConfig: iceConfig, - modifiedAt: at, - } -} - -func (icc *IceConfigCache[T]) Get(key T) *livekit.ICEConfig { - icc.lock.Lock() - defer icc.lock.Unlock() - - entry, ok := icc.entries[key] - if !ok || time.Since(entry.modifiedAt) > icc.ttl { - delete(icc.entries, key) - return &livekit.ICEConfig{} - } - - return entry.iceConfig -} - -func (icc *IceConfigCache[T]) pruneWorker() { - ticker := time.NewTicker(icc.ttl / 2) - defer ticker.Stop() - - for !icc.stopped.Load() { - <-ticker.C - - icc.lock.Lock() - for key, entry := range icc.entries { - if time.Since(entry.modifiedAt) > icc.ttl { - delete(icc.entries, key) - } - } - icc.lock.Unlock() - } -} diff --git a/pkg/utils/iceconfigcache.go b/pkg/utils/iceconfigcache.go new file mode 100644 index 000000000..e42ed2bb6 --- /dev/null +++ b/pkg/utils/iceconfigcache.go @@ -0,0 +1,42 @@ +package utils + +import ( + "time" + + "github.com/jellydator/ttlcache/v3" + + "github.com/livekit/protocol/livekit" +) + +const ( + iceConfigTTLMin = 5 * time.Minute +) + +type IceConfigCache[T comparable] struct { + c *ttlcache.Cache[T, *livekit.ICEConfig] +} + +func NewIceConfigCache[T comparable](ttl time.Duration) *IceConfigCache[T] { + cache := ttlcache.New( + ttlcache.WithTTL[T, *livekit.ICEConfig](max(ttl, iceConfigTTLMin)), + ttlcache.WithDisableTouchOnHit[T, *livekit.ICEConfig](), + ) + go cache.Start() + + return &IceConfigCache[T]{cache} +} + +func (icc *IceConfigCache[T]) Stop() { + icc.c.Stop() +} + +func (icc *IceConfigCache[T]) Put(key T, iceConfig *livekit.ICEConfig) { + icc.c.Set(key, iceConfig, ttlcache.DefaultTTL) +} + +func (icc *IceConfigCache[T]) Get(key T) *livekit.ICEConfig { + if it := icc.c.Get(key); it != nil { + return it.Value() + } + return &livekit.ICEConfig{} +} diff --git a/pkg/utils/iceconfigcache_test.go b/pkg/utils/iceconfigcache_test.go new file mode 100644 index 000000000..78feebb0e --- /dev/null +++ b/pkg/utils/iceconfigcache_test.go @@ -0,0 +1,18 @@ +package utils + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/livekit/protocol/livekit" +) + +func TestIceConfigCache(t *testing.T) { + cache := NewIceConfigCache[string](10 * time.Second) + t.Cleanup(cache.Stop) + + cache.Put("test", &livekit.ICEConfig{}) + require.NotNil(t, cache) +}