Feat: room hot list use heap

pull/24/head
zijiren233 2 years ago
parent b596d9ea03
commit 16bd51fa81

@ -8,6 +8,7 @@ import (
"github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/db"
"github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/model"
synccache "github.com/synctv-org/synctv/utils/syncCache" synccache "github.com/synctv-org/synctv/utils/syncCache"
"github.com/zijiren233/gencontainer/heap"
) )
var roomTTL = time.Hour * 24 * 2 var roomTTL = time.Hour * 24 * 2
@ -150,3 +151,57 @@ func GetAllRoomsInCacheWithoutHidden() []*Room {
}) })
return rooms return rooms
} }
type RoomHeapItem struct {
ID uint
RoomName string
ClientNum int64
NeedPassword bool
CreatorID uint
CreatedAt time.Time
}
type RoomHeap []*RoomHeapItem
func (h RoomHeap) Len() int {
return len(h)
}
func (h RoomHeap) Less(i, j int) bool {
return h[i].ClientNum < h[j].ClientNum
}
func (h RoomHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
func (h *RoomHeap) Push(x *RoomHeapItem) {
*h = append(*h, x)
}
func (h *RoomHeap) Pop() *RoomHeapItem {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func GetRoomHeapInCacheWithoutHidden() RoomHeap {
rooms := make(RoomHeap, 0)
roomCache.Range(func(key uint, value *synccache.Entry[*Room]) bool {
v := value.Value()
if !v.Settings.Hidden {
heap.Push[*RoomHeapItem](&rooms, &RoomHeapItem{
ID: v.ID,
RoomName: v.Name,
ClientNum: v.ClientNum(),
NeedPassword: v.NeedPassword(),
CreatorID: v.CreatorID,
CreatedAt: v.CreatedAt,
})
}
return true
})
return rooms
}

@ -13,7 +13,6 @@ import (
"github.com/synctv-org/synctv/server/middlewares" "github.com/synctv-org/synctv/server/middlewares"
"github.com/synctv-org/synctv/server/model" "github.com/synctv-org/synctv/server/model"
"github.com/synctv-org/synctv/utils" "github.com/synctv-org/synctv/utils"
"github.com/zijiren233/gencontainer/vec"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -75,31 +74,23 @@ func RoomHotList(ctx *gin.Context) {
return return
} }
r := op.GetAllRoomsInCacheWithoutHidden() r := op.GetRoomHeapInCacheWithoutHidden()
rs := vec.New[*model.RoomListResp](vec.WithCmpLess[*model.RoomListResp](func(v1, v2 *model.RoomListResp) bool { rs := utils.GetPageItems(r, page, pageSize)
return v1.PeopleNum < v2.PeopleNum resp := make([]*model.RoomListResp, len(rs))
}), vec.WithCmpEqual[*model.RoomListResp](func(v1, v2 *model.RoomListResp) bool { for i, v := range rs {
return v1.PeopleNum == v2.PeopleNum resp[i] = &model.RoomListResp{
}))
for _, v := range r {
rs.Push(&model.RoomListResp{
RoomId: v.ID, RoomId: v.ID,
RoomName: v.Name, RoomName: v.RoomName,
PeopleNum: v.ClientNum(), PeopleNum: v.ClientNum,
NeedPassword: v.NeedPassword(), NeedPassword: v.NeedPassword,
Creator: op.GetUserName(v.Room.CreatorID), Creator: op.GetUserName(v.CreatorID),
CreatedAt: v.Room.CreatedAt.UnixMilli(), CreatedAt: v.CreatedAt.UnixMilli(),
}) }
}
rs.SortStable()
if ctx.DefaultQuery("sort", "desc") == "desc" {
rs.Reverse()
} }
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{ ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"total": rs.Len(), "total": len(r),
"list": utils.GetPageItems(rs.Slice(), page, pageSize), "list": rs,
})) }))
} }

@ -35,18 +35,10 @@ func NewSyncCache[K comparable, V any](trimTime time.Duration, conf ...SyncCache
return sc return sc
} }
func (sc *SyncCache[K, V]) Releases() {
sc.ticker.Stop()
sc.cache.Clear()
}
func (sc *SyncCache[K, V]) trim() { func (sc *SyncCache[K, V]) trim() {
sc.cache.Range(func(key K, value *Entry[V]) bool { sc.cache.Range(func(key K, value *Entry[V]) bool {
if value.IsExpired() { if value.IsExpired() {
sc.cache.CompareAndDelete(key, value) sc.CompareAndDelete(key, value)
if sc.deletedCallback != nil {
sc.deletedCallback(value.value)
}
} }
return true return true
}) })
@ -61,33 +53,19 @@ func (sc *SyncCache[K, V]) Load(key K) (value *Entry[V], loaded bool) {
if ok && !e.IsExpired() { if ok && !e.IsExpired() {
return e, ok return e, ok
} }
sc.CompareAndDelete(key, e)
return return
} }
func (sc *SyncCache[K, V]) LoadOrStore(key K, value V, expire time.Duration) (actual *Entry[V], loaded bool) { func (sc *SyncCache[K, V]) LoadOrStore(key K, value V, expire time.Duration) (actual *Entry[V], loaded bool) {
e, loaded := sc.cache.LoadOrStore(key, NewEntry[V](value, expire)) e, loaded := sc.cache.LoadOrStore(key, NewEntry[V](value, expire))
if e.IsExpired() { if loaded && e.IsExpired() {
e = NewEntry[V](value, expire) sc.CompareAndDelete(key, e)
sc.cache.Store(key, e) return sc.LoadOrStore(key, value, expire)
return e, false
} }
return e, loaded return e, loaded
} }
func (sc *SyncCache[K, V]) AddExpiration(key K, d time.Duration) {
e, ok := sc.cache.Load(key)
if ok {
e.AddExpiration(d)
}
}
func (sc *SyncCache[K, V]) SetExpiration(key K, t time.Time) {
e, ok := sc.cache.Load(key)
if ok {
e.SetExpiration(t)
}
}
func (sc *SyncCache[K, V]) Delete(key K) { func (sc *SyncCache[K, V]) Delete(key K) {
sc.LoadAndDelete(key) sc.LoadAndDelete(key)
} }
@ -117,6 +95,7 @@ func (sc *SyncCache[K, V]) Range(f func(key K, value *Entry[V]) bool) {
if !value.IsExpired() { if !value.IsExpired() {
return f(key, value) return f(key, value)
} }
sc.cache.CompareAndDelete(key, value)
return true return true
}) })
} }

Loading…
Cancel
Save