Files
origin/sysservice/rankservice/RankSkip.go
2022-11-23 16:31:15 +08:00

305 lines
8.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package rankservice
import (
"fmt"
"github.com/duanhf2012/origin/rpc"
"github.com/duanhf2012/origin/util/algorithms/skip"
"time"
)
type RankSkip struct {
rankId uint64 //排行榜ID
rankName string //排行榜名称
isDes bool //是否为降序 true降序 false升序
skipList *skip.SkipList //跳表
mapRankData map[uint64]*RankData //排行数据map
maxLen uint64 //排行数据长度
expireMs time.Duration //有效时间
rankModule IRankModule
rankDataExpire rankDataHeap
}
const MaxPickExpireNum = 128
const (
RankDataNone RankDataChangeType = 0
RankDataAdd RankDataChangeType = 1 //数据插入
RankDataUpdate RankDataChangeType = 2 //数据更新
RankDataDelete RankDataChangeType = 3 //数据删除
)
// NewRankSkip 创建排行榜
func NewRankSkip(rankId uint64,rankName string,isDes bool, level interface{}, maxLen uint64,expireMs time.Duration) *RankSkip {
rs := &RankSkip{}
rs.rankId = rankId
rs.rankName = rankName
rs.isDes = isDes
rs.skipList = skip.New(level)
rs.mapRankData = make(map[uint64]*RankData, 10240)
rs.maxLen = maxLen
rs.expireMs = expireMs
rs.rankDataExpire.Init(int32(maxLen),expireMs)
return rs
}
func (rs *RankSkip) pickExpireKey(){
if rs.expireMs == 0 {
return
}
for i:=1;i<=MaxPickExpireNum;i++{
key := rs.rankDataExpire.PopExpireKey()
if key == 0 {
return
}
rs.DeleteRankData([]uint64{key})
}
}
func (rs *RankSkip) SetupRankModule(rankModule IRankModule) {
rs.rankModule = rankModule
}
// GetRankID 获取排行榜Id
func (rs *RankSkip) GetRankID() uint64 {
return rs.rankId
}
// GetRankName 获取排行榜名称
func (rs *RankSkip) GetRankName() string {
return rs.rankName
}
// GetRankLen 获取排行榜长度
func (rs *RankSkip) GetRankLen() uint64 {
return rs.skipList.Len()
}
func (rs *RankSkip) UpsetRankList(upsetRankData []*rpc.RankData) (addCount int32, modifyCount int32) {
for _, upsetData := range upsetRankData {
changeType := rs.UpsetRank(upsetData,time.Now().UnixNano(),false)
if changeType == RankDataAdd{
addCount+=1
} else if changeType == RankDataUpdate{
modifyCount+=1
}
}
rs.pickExpireKey()
return
}
// UpsetRank 更新玩家排行数据,返回变化后的数据及变化类型
func (rs *RankSkip) UpsetRank(upsetData *rpc.RankData,refreshTimestamp int64,fromLoad bool) RankDataChangeType {
rankNode, ok := rs.mapRankData[upsetData.Key]
if ok == true {
//找到的情况对比排名数据是否有变化,无变化进行data更新,有变化则进行删除更新
if compareIsEqual(rankNode.SortData, upsetData.SortData) {
rankNode.Data = upsetData.GetData()
rankNode.refreshTimestamp = refreshTimestamp
if fromLoad == false {
rs.rankModule.OnChangeRankData(rs,rankNode)
}
rs.rankDataExpire.PushOrRefreshExpireKey(upsetData.Key,refreshTimestamp)
return RankDataUpdate
}
if upsetData.Data == nil {
upsetData.Data = rankNode.Data
}
rs.skipList.Delete(rankNode)
ReleaseRankData(rankNode)
newRankData := NewRankData(rs.isDes, upsetData,refreshTimestamp)
rs.skipList.Insert(newRankData)
rs.mapRankData[upsetData.Key] = newRankData
//刷新有效期
rs.rankDataExpire.PushOrRefreshExpireKey(upsetData.Key,refreshTimestamp)
if fromLoad == false {
rs.rankModule.OnChangeRankData(rs, newRankData)
}
return RankDataUpdate
}
if rs.checkInsertAndReplace(upsetData) {
newRankData := NewRankData(rs.isDes, upsetData,refreshTimestamp)
rs.skipList.Insert(newRankData)
rs.mapRankData[upsetData.Key] = newRankData
rs.rankDataExpire.PushOrRefreshExpireKey(upsetData.Key,refreshTimestamp)
if fromLoad == false {
rs.rankModule.OnEnterRank(rs, newRankData)
}
return RankDataAdd
}
return RankDataNone
}
// DeleteRankData 删除排行数据
func (rs *RankSkip) DeleteRankData(delKeys []uint64) int32 {
var removeRankData int32
//预统计处理,进行回调
for _, key := range delKeys {
rankData, ok := rs.mapRankData[key]
if ok == false {
continue
}
removeRankData+=1
rs.skipList.Delete(rankData)
delete(rs.mapRankData, rankData.Key)
rs.rankDataExpire.RemoveExpireKey(rankData.Key)
rs.rankModule.OnLeaveRank(rs, rankData)
ReleaseRankData(rankData)
}
return removeRankData
}
// GetRankNodeData 获取,返回排名节点与名次
func (rs *RankSkip) GetRankNodeData(findKey uint64) (*RankData, uint64) {
rankNode, ok := rs.mapRankData[findKey]
if ok == false {
return nil, 0
}
rs.pickExpireKey()
_, index := rs.skipList.GetWithPosition(rankNode)
return rankNode, index+1
}
// GetRankNodeDataByPos 获取,返回排名节点与名次
func (rs *RankSkip) GetRankNodeDataByRank(rank uint64) (*RankData, uint64) {
rs.pickExpireKey()
rankNode := rs.skipList.ByPosition(rank-1)
if rankNode == nil {
return nil, 0
}
return rankNode.(*RankData), rank
}
// GetRankKeyPrevToLimit 获取key前count名的数据
func (rs *RankSkip) GetRankKeyPrevToLimit(findKey, count uint64, result *rpc.RankDataList) error {
if rs.GetRankLen() <= 0 {
return fmt.Errorf("rank[", rs.rankId, "] no data")
}
findData, ok := rs.mapRankData[findKey]
if ok == false {
return fmt.Errorf("rank[", rs.rankId, "] no data")
}
_, rankPos := rs.skipList.GetWithPosition(findData)
iter := rs.skipList.Iter(findData)
iterCount := uint64(0)
for iter.Prev() && iterCount < count {
rankData := iter.Value().(*RankData)
result.RankPosDataList = append(result.RankPosDataList, &rpc.RankPosData{
Key: rankData.Key,
Rank: rankPos - iterCount+1,
SortData: rankData.SortData,
Data: rankData.Data,
})
iterCount++
}
return nil
}
// GetRankKeyPrevToLimit 获取key前count名的数据
func (rs *RankSkip) GetRankKeyNextToLimit(findKey, count uint64, result *rpc.RankDataList) error {
if rs.GetRankLen() <= 0 {
return fmt.Errorf("rank[", rs.rankId, "] no data")
}
findData, ok := rs.mapRankData[findKey]
if ok == false {
return fmt.Errorf("rank[", rs.rankId, "] no data")
}
_, rankPos := rs.skipList.GetWithPosition(findData)
iter := rs.skipList.Iter(findData)
iterCount := uint64(0)
for iter.Next() && iterCount < count {
rankData := iter.Value().(*RankData)
result.RankPosDataList = append(result.RankPosDataList, &rpc.RankPosData{
Key: rankData.Key,
Rank: rankPos + iterCount+1,
SortData: rankData.SortData,
Data: rankData.Data,
})
iterCount++
}
return nil
}
// GetRankList 获取排行榜数据,startPos开始的count个数据
func (rs *RankSkip) GetRankDataFromToLimit(startPos, count uint64, result *rpc.RankDataList) error {
if rs.GetRankLen() <= 0 {
//初始排行榜可能没有数据
return nil
}
rs.pickExpireKey()
if result.RankDataCount < startPos {
startPos = result.RankDataCount - 1
}
iter := rs.skipList.IterAtPosition(startPos)
iterCount := uint64(0)
for iter.Next() && iterCount < count {
rankData := iter.Value().(*RankData)
result.RankPosDataList = append(result.RankPosDataList, &rpc.RankPosData{
Key: rankData.Key,
Rank: iterCount + startPos+1,
SortData: rankData.SortData,
Data: rankData.Data,
})
iterCount++
}
return nil
}
// checkCanInsert 检查是否能插入
func (rs *RankSkip) checkInsertAndReplace(upsetData *rpc.RankData) bool {
//maxLen为0不限制长度
if rs.maxLen == 0 {
return true
}
//没有放满,则进行插入
rankLen := rs.skipList.Len()
if rs.maxLen > rankLen {
return true
}
//已经放满了,进行数据比较
lastPosData := rs.skipList.ByPosition(rankLen - 1)
lastRankData := lastPosData.(*RankData)
moreThanFlag := compareMoreThan(upsetData.SortData, lastRankData.SortData)
//降序排列,比最后一位小,不能插入 升序排列,比最后一位大,不能插入
if (rs.isDes == true && moreThanFlag < 0) || (rs.isDes == false && moreThanFlag > 0) || moreThanFlag == 0 {
return false
}
//移除最后一位
//回调模块该RandData从排行中删除
rs.rankDataExpire.RemoveExpireKey(lastRankData.Key)
rs.rankModule.OnLeaveRank(rs, lastRankData)
rs.skipList.Delete(lastPosData)
delete(rs.mapRankData, lastRankData.Key)
ReleaseRankData(lastRankData)
return true
}