Files
origin/sysservice/rankservice/RankSkip.go
2024-04-22 21:47:49 +08:00

474 lines
13 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"
"time"
"github.com/duanhf2012/origin/rpc"
"github.com/duanhf2012/origin/util/algorithms/skip"
)
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
}
func (rs *RankSkip) InsertDataOnNonExistent(changeRankData *rpc.IncreaseRankData) bool {
if changeRankData.InsertDataOnNonExistent == false {
return false
}
var upsetData rpc.RankData
upsetData.Key = changeRankData.Key
upsetData.Data = changeRankData.InitData
upsetData.SortData = changeRankData.InitSortData
for i := 0; i < len(changeRankData.IncreaseSortData) && i < len(upsetData.SortData); i++ {
upsetData.SortData[i] += changeRankData.IncreaseSortData[i]
}
for _, val := range changeRankData.Extend {
upsetData.ExData = append(upsetData.ExData, &rpc.ExtendIncData{InitValue: val.InitValue, IncreaseValue: val.IncreaseValue})
}
//强制设计指定值
for _, setData := range changeRankData.SetSortAndExtendData {
if setData.IsSortData == true {
if int(setData.Pos) >= len(upsetData.SortData) {
return false
}
upsetData.SortData[setData.Pos] = setData.Data
} else {
if int(setData.Pos) < len(upsetData.ExData) {
upsetData.ExData[setData.Pos].IncreaseValue = 0
upsetData.ExData[setData.Pos].InitValue = setData.Data
}
}
}
refreshTimestamp := time.Now().UnixNano()
newRankData := NewRankData(rs.isDes, &upsetData, refreshTimestamp)
rs.skipList.Insert(newRankData)
rs.mapRankData[upsetData.Key] = newRankData
//刷新有效期和存档数据
rs.rankDataExpire.PushOrRefreshExpireKey(upsetData.Key, refreshTimestamp)
rs.rankModule.OnChangeRankData(rs, newRankData)
return true
}
func (rs *RankSkip) UpdateRankData(updateRankData *rpc.UpdateRankData) bool {
rankNode, ok := rs.mapRankData[updateRankData.Key]
if ok == false {
return false
}
rankNode.Data = updateRankData.Data
rs.rankDataExpire.PushOrRefreshExpireKey(updateRankData.Key, time.Now().UnixNano())
rs.rankModule.OnChangeRankData(rs, rankNode)
return true
}
func (rs *RankSkip) ChangeExtendData(changeRankData *rpc.IncreaseRankData) bool {
rankNode, ok := rs.mapRankData[changeRankData.Key]
if ok == false {
return rs.InsertDataOnNonExistent(changeRankData)
}
//先判断是不是有修改
bChange := false
for i := 0; i < len(changeRankData.IncreaseSortData) && i < len(rankNode.SortData); i++ {
if changeRankData.IncreaseSortData[i] != 0 {
bChange = true
}
}
if bChange == false {
for _, setSortAndExtendData := range changeRankData.SetSortAndExtendData {
if setSortAndExtendData.IsSortData == true {
bChange = true
}
}
}
//如果有改变,删除原有的数据,重新刷新到跳表
rankData := rankNode
refreshTimestamp := time.Now().UnixNano()
if bChange == true {
//copy数据
var upsetData rpc.RankData
upsetData.Key = rankNode.Key
upsetData.Data = rankNode.Data
upsetData.SortData = append(upsetData.SortData, rankNode.SortData...)
for i := 0; i < len(changeRankData.IncreaseSortData) && i < len(upsetData.SortData); i++ {
if changeRankData.IncreaseSortData[i] != 0 {
upsetData.SortData[i] += changeRankData.IncreaseSortData[i]
}
}
for _, setData := range changeRankData.SetSortAndExtendData {
if setData.IsSortData == true {
if int(setData.Pos) < len(upsetData.SortData) {
upsetData.SortData[setData.Pos] = setData.Data
}
}
}
rankData = NewRankData(rs.isDes, &upsetData, refreshTimestamp)
rankData.ExData = append(rankData.ExData, rankNode.ExData...)
//从排行榜中删除
rs.skipList.Delete(rankNode)
ReleaseRankData(rankNode)
rs.skipList.Insert(rankData)
rs.mapRankData[upsetData.Key] = rankData
}
//增长扩展参数
for i := 0; i < len(changeRankData.Extend); i++ {
if i < len(rankData.ExData) {
//直接增长
rankData.ExData[i] += changeRankData.Extend[i].IncreaseValue
} else {
//如果不存在的扩展位置,append补充并按IncreaseValue增长
rankData.ExData = append(rankData.ExData, changeRankData.Extend[i].InitValue+changeRankData.Extend[i].IncreaseValue)
}
}
//设置固定值
for _, setData := range changeRankData.SetSortAndExtendData {
if setData.IsSortData == false {
if int(setData.Pos) < len(rankData.ExData) {
rankData.ExData[setData.Pos] = setData.Data
}
}
}
rs.rankDataExpire.PushOrRefreshExpireKey(rankData.Key, refreshTimestamp)
rs.rankModule.OnChangeRankData(rs, rankData)
return true
}
// UpsetRank 更新玩家排行数据,返回变化后的数据及变化类型
func (rs *RankSkip) UpsetRank(upsetData *rpc.RankData, refreshTimestamp int64, fromLoad bool) RankDataChangeType {
rankNode, ok := rs.mapRankData[upsetData.Key]
if ok == true {
//增长扩展数据
for i := 0; i < len(upsetData.ExData); i++ {
if i < len(rankNode.ExData) {
//直接增长
rankNode.ExData[i] += upsetData.ExData[i].IncreaseValue
} else {
//如果不存在的扩展位置,append补充并按IncreaseValue增长
rankNode.ExData = append(rankNode.ExData, upsetData.ExData[i].InitValue+upsetData.ExData[i].IncreaseValue)
}
}
//找到的情况对比排名数据是否有变化,无变化进行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
}
//设置额外数据
for idx, exValue := range rankNode.ExData {
currentIncreaseValue := int64(0)
if idx < len(upsetData.ExData) {
currentIncreaseValue = upsetData.ExData[idx].IncreaseValue
}
upsetData.ExData = append(upsetData.ExData, &rpc.ExtendIncData{
InitValue: exValue,
IncreaseValue: currentIncreaseValue,
})
}
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[%d] no data", rs.rankId)
}
findData, ok := rs.mapRankData[findKey]
if ok == false {
return fmt.Errorf("rank[%d] no data", rs.rankId)
}
_, 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,
ExtendData: rankData.ExData,
})
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[%d] no data", rs.rankId)
}
findData, ok := rs.mapRankData[findKey]
if ok == false {
return fmt.Errorf("rank[%d] no data", rs.rankId)
}
_, 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,
ExtendData: rankData.ExData,
})
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,
ExtendData: rankData.ExData,
})
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
}