feat: add local cache for high frequency reads (#2036)

* feat: msg local cache

* feat: msg local cache

* feat: msg local cache

* feat: msg local cache

* feat: msg local cache

* feat: msg local cache

* fix: mongo

* fix: mongo

* fix: mongo

* openim.yaml

* localcache

* localcache

* localcache

* localcache

* localcache

* localcache

* localcache

* localcache

* localcache

* local cache

* local cache

* local cache

* local cache

* fix: GroupApplicationAcceptedNotification

* fix: GroupApplicationAcceptedNotification

* fix: NotificationUserInfoUpdate

* feat: cache add single-flight and timing-wheel.

* feat: local cache

* feat: local cache

* feat: local cache

* feat: cache add single-flight and timing-wheel.

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: local cache

* feat: msg rpc local cache

* feat: msg rpc local cache

* feat: msg rpc local cache

* feat: msg rpc local cache

* feat: msg rpc local cache

* feat: msg rpc local cache

* refactor: refactor the code of push and optimization.

* cicd: robot automated Change

* refactor: rename cache.

* merge

* fix: refactor project dir avoid import cycle.

* update tools

* merge

* feat: conversation FindRecvMsgNotNotifyUserIDs

* feat: conversation FindRecvMsgNotNotifyUserIDs

* feat: conversation FindRecvMsgNotNotifyUserIDs

* merge

* merge the latest main

---------

Co-authored-by: Gordon <46924906+FGadvancer@users.noreply.github.com>
Co-authored-by: withchao <withchao@users.noreply.github.com>
This commit is contained in:
chao
2024-03-08 16:30:47 +08:00
committed by GitHub
parent 291443dd6b
commit b9cf40034c
60 changed files with 1860 additions and 390 deletions
+112
View File
@@ -0,0 +1,112 @@
package localcache
import (
"context"
"github.com/openimsdk/localcache/link"
"github.com/openimsdk/localcache/lru"
"hash/fnv"
"unsafe"
)
type Cache[V any] interface {
Get(ctx context.Context, key string, fetch func(ctx context.Context) (V, error)) (V, error)
GetLink(ctx context.Context, key string, fetch func(ctx context.Context) (V, error), link ...string) (V, error)
Del(ctx context.Context, key ...string)
DelLocal(ctx context.Context, key ...string)
Stop()
}
func New[V any](opts ...Option) Cache[V] {
opt := defaultOption()
for _, o := range opts {
o(opt)
}
c := cache[V]{opt: opt}
if opt.localSlotNum > 0 && opt.localSlotSize > 0 {
createSimpleLRU := func() lru.LRU[string, V] {
if opt.expirationEvict {
return lru.NewExpirationLRU[string, V](opt.localSlotSize, opt.localSuccessTTL, opt.localFailedTTL, opt.target, c.onEvict)
} else {
return lru.NewLayLRU[string, V](opt.localSlotSize, opt.localSuccessTTL, opt.localFailedTTL, opt.target, c.onEvict)
}
}
if opt.localSlotNum == 1 {
c.local = createSimpleLRU()
} else {
c.local = lru.NewSlotLRU[string, V](opt.localSlotNum, func(key string) uint64 {
h := fnv.New64a()
h.Write(*(*[]byte)(unsafe.Pointer(&key)))
return h.Sum64()
}, createSimpleLRU)
}
if opt.linkSlotNum > 0 {
c.link = link.New(opt.linkSlotNum)
}
}
return &c
}
type cache[V any] struct {
opt *option
link link.Link
local lru.LRU[string, V]
}
func (c *cache[V]) onEvict(key string, value V) {
if c.link != nil {
lks := c.link.Del(key)
for k := range lks {
if key != k { // prevent deadlock
c.local.Del(k)
}
}
}
}
func (c *cache[V]) del(key ...string) {
if c.local == nil {
return
}
for _, k := range key {
c.local.Del(k)
if c.link != nil {
lks := c.link.Del(k)
for k := range lks {
c.local.Del(k)
}
}
}
}
func (c *cache[V]) Get(ctx context.Context, key string, fetch func(ctx context.Context) (V, error)) (V, error) {
return c.GetLink(ctx, key, fetch)
}
func (c *cache[V]) GetLink(ctx context.Context, key string, fetch func(ctx context.Context) (V, error), link ...string) (V, error) {
if c.local != nil {
return c.local.Get(key, func() (V, error) {
if len(link) > 0 {
c.link.Link(key, link...)
}
return fetch(ctx)
})
} else {
return fetch(ctx)
}
}
func (c *cache[V]) Del(ctx context.Context, key ...string) {
for _, fn := range c.opt.delFn {
fn(ctx, key...)
}
c.del(key...)
}
func (c *cache[V]) DelLocal(ctx context.Context, key ...string) {
c.del(key...)
}
func (c *cache[V]) Stop() {
c.local.Stop()
}