新增排行榜服务

This commit is contained in:
orgin
2022-11-18 15:45:20 +08:00
parent 5601ab5ae2
commit 95b4e2f8de
11 changed files with 4410 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
package rankservice
import (
"github.com/duanhf2012/origin/rpc"
"github.com/duanhf2012/origin/util/algorithms/skip"
"github.com/duanhf2012/origin/util/sync"
)
var emptyRankData RankData
var RankDataPool = sync.NewPoolEx(make(chan sync.IPoolData, 10240), func() sync.IPoolData {
var newRankData RankData
return &newRankData
})
type RankData struct {
*rpc.RankData
ref bool
compareFunc func(other skip.Comparator) int
}
func NewRankData(isDec bool, data *rpc.RankData) *RankData {
ret := RankDataPool.Get().(*RankData)
ret.compareFunc = ret.ascCompare
if isDec {
ret.compareFunc = ret.desCompare
}
ret.RankData = data
return ret
}
func ReleaseRankData(rankData *RankData) {
RankDataPool.Put(rankData)
}
func (p *RankData) Reset() {
*p = emptyRankData
}
func (p *RankData) IsRef() bool {
return p.ref
}
func (p *RankData) Ref() {
p.ref = true
}
func (p *RankData) UnRef() {
p.ref = false
}
func (p *RankData) Compare(other skip.Comparator) int {
return p.compareFunc(other)
}
func (p *RankData) GetKey() uint64 {
return p.Key
}
func (p *RankData) ascCompare(other skip.Comparator) int {
otherRankData := other.(*RankData)
if otherRankData.Key == p.Key {
return 0
}
retFlg := compareMoreThan(p.SortData, otherRankData.SortData)
if retFlg == 0 {
if p.Key > otherRankData.Key {
retFlg = 1
} else {
retFlg = -1
}
}
return retFlg
}
func (p *RankData) desCompare(other skip.Comparator) int {
otherRankData := other.(*RankData)
if otherRankData.Key == p.Key {
return 0
}
retFlg := compareMoreThan(otherRankData.SortData, p.SortData)
if retFlg == 0 {
if p.Key > otherRankData.Key {
retFlg = -1
} else {
retFlg = 1
}
}
return retFlg
}

View File

@@ -0,0 +1,52 @@
package rankservice
func transformLevel(level int32) interface{} {
switch level {
case 8:
return uint8(0)
case 16:
return uint16(0)
case 32:
return uint32(0)
case 64:
return uint64(0)
default:
return uint32(0)
}
}
func compareIsEqual(firstSortData, secondSortData []int64) bool {
firstLen := len(firstSortData)
if firstLen != len(secondSortData) {
return false
}
for i := firstLen - 1; i >= 0; i-- {
if firstSortData[i] != secondSortData[i] {
return false
}
}
return true
}
func compareMoreThan(firstSortData, secondSortData []int64) int {
firstLen := len(firstSortData)
secondLen := len(secondSortData)
minLen := firstLen
if firstLen > secondLen {
minLen = secondLen
}
for i := 0; i < minLen; i++ {
if firstSortData[i] > secondSortData[i] {
return 1
}
if firstSortData[i] < secondSortData[i] {
return -1
}
}
return 0
}

View File

@@ -0,0 +1,52 @@
package rankservice
import "github.com/duanhf2012/origin/service"
type RankDataChangeType int8
const (
RankDataNone RankDataChangeType = 0
RankDataAdd RankDataChangeType = 1 //数据插入
RankDataUpdate RankDataChangeType = 2 //数据更新
RankDataDelete RankDataChangeType = 3 //数据删除
)
type IRankSkip interface {
GetRankID() uint64
GetRankLen() uint64
}
// RankDataChangeCallBack 排行数据变化时调用
//type RankDataChangeCallBack interface {
// CB(iRankService service.IService, rankSkip IRankSkip, changeType RankDataChangeType, changed []*RankData)
//}
type IRankModule interface {
service.IModule
OnStart(mapRankSkip map[uint64]*RankSkip) error //服务开启时回调
OnEnterRank(rankSkip IRankSkip, enterData []*RankData) //进入排行
OnLeaveRank(rankSkip IRankSkip, leaveData []*RankData) //离开排行
OnChangeRankData(rankSkip IRankSkip, changeData []*RankData) //当排行数据变化时
OnStop(mapRankSkip map[uint64]*RankSkip) //服务结束时回调
}
type DefaultRankModule struct {
service.Module
}
func (dr *DefaultRankModule) OnStart(mapRankSkip map[uint64]*RankSkip) error {
return nil
}
func (dr *DefaultRankModule) OnEnterRank(rankSkip IRankSkip, enterData []*RankData) {
}
func (dr *DefaultRankModule) OnLeaveRank(rankSkip IRankSkip, leaveData []*RankData) {
}
func (dr *DefaultRankModule) OnChangeRankData(rankSkip IRankSkip, changeData []*RankData) {
}
func (dr *DefaultRankModule) OnStop(mapRankSkip map[uint64]*RankSkip) {
}

View File

@@ -0,0 +1,195 @@
package rankservice
import (
"fmt"
"github.com/duanhf2012/origin/log"
"github.com/duanhf2012/origin/node"
"github.com/duanhf2012/origin/rpc"
"github.com/duanhf2012/origin/service"
)
func init() {
node.Setup(&RankService{})
}
const PreMapRankSkipLen = 10
const ManualAddRankSkip = "RPC_ManualAddRankSkip"
const UpsetRank = "RPC_UpsetRank"
const DeleteRankDataByKey = "RPC_DeleteRankDataByKey"
const FindRankDataByKey = "RPC_FindRankDataByKey"
const FindRankDataByPos = "RPC_FindRankDataByPos"
const FindRankDataListStartTo = "RPC_FindRankDataListStartTo"
type RankService struct {
service.Service
mapRankSkip map[uint64]*RankSkip
rankModule IRankModule
}
func (rs *RankService) OnInit() error {
rs.mapRankSkip = make(map[uint64]*RankSkip, PreMapRankSkipLen)
err := rs.dealCfg()
if err != nil {
return err
}
if rs.rankModule != nil {
_, err = rs.AddModule(rs.rankModule)
if err != nil {
return err
}
} else {
rs.AddModule(&DefaultRankModule{})
}
return nil
}
func (rs *RankService) OnStart() {
rs.rankModule.OnStart(rs.mapRankSkip)
}
func (rs *RankService) OnRelease() {
rs.rankModule.OnStop(rs.mapRankSkip)
}
// 安装排行模块
func (rs *RankService) SetupRankModule(rankModule IRankModule) {
rs.rankModule = rankModule
}
// RPC_ManualAddRankSkip 提供手动添加排行榜
func (rs *RankService) RPC_ManualAddRankSkip(addInfo *rpc.AddRankList, addResult *rpc.RankResult) error {
addList := make([]uint64, 0, PreMapRankSkipLen)
for _, addRankListData := range addInfo.AddList {
if addRankListData.RankId == 0 {
rs.deleteRankList(addList)
return fmt.Errorf("RPC_AddRankSkip must has rank id")
}
newSkip := NewRankSkip(addRankListData.IsDec, transformLevel(addRankListData.SkipListLevel), addRankListData.MaxRank)
rs.mapRankSkip[addRankListData.RankId] = newSkip
addList = append(addList, addRankListData.RankId)
}
addResult.AddCount = 1
return nil
}
// RPC_UpsetRank 更新排行榜
func (rs *RankService) RPC_UpsetRank(upsetInfo *rpc.UpsetRankData, upsetResult *rpc.RankResult) error {
rankSkip, ok := rs.mapRankSkip[upsetInfo.RankId]
if ok == false || rankSkip == nil {
return fmt.Errorf("RPC_UpsetRank[", upsetInfo.RankId, "] no this rank id")
}
addCount, updateCount := rankSkip.UpsetRank(upsetInfo.RankDataList)
upsetResult.AddCount = addCount
upsetResult.ModifyCount = updateCount
return nil
}
// RPC_DeleteRankDataByKey 按排行的key进行删除
func (rs *RankService) RPC_DeleteRankDataByKey(delInfo *rpc.DeleteByKey, delResult *rpc.RankResult) error {
rankSkip, ok := rs.mapRankSkip[delInfo.RankId]
if ok == false || rankSkip == nil {
return fmt.Errorf("RPC_DeleteRankDataByKey[", delInfo.RankId, "] no this rank type")
}
removeCount := rankSkip.DeleteRankData(delInfo.KeyList)
if removeCount == 0 {
log.SError("remove count is zero")
}
delResult.RemoveCount = removeCount
return nil
}
// RPC_FindRankDataByKey 按key查找
func (rs *RankService) RPC_FindRankDataByKey(findInfo *rpc.FindRankDataByKey, findResult *rpc.RankPosData) error {
rankObj, ok := rs.mapRankSkip[findInfo.RankId]
if ok == false || rankObj == nil {
return fmt.Errorf("RPC_FindRankDataByKey[", findInfo.RankId, "] no this rank type")
}
findRankData, rankPos := rankObj.GetRankNodeData(findInfo.Key)
if findRankData != nil {
findResult.Data = findRankData.Data
findResult.Key = findRankData.Key
findResult.SortData = findRankData.SortData
findResult.RankPos = rankPos
}
return nil
}
// RPC_FindRankDataByPos 按pos查找
func (rs *RankService) RPC_FindRankDataByPos(findInfo *rpc.FindRankDataByPos, findResult *rpc.RankPosData) error {
rankObj, ok := rs.mapRankSkip[findInfo.RankId]
if ok == false || rankObj == nil {
return fmt.Errorf("RPC_FindRankDataByKey[", findInfo.RankId, "] no this rank type")
}
findRankData, rankPos := rankObj.GetRankNodeDataByPos(findInfo.Pos)
if findRankData != nil {
findResult.Data = findRankData.Data
findResult.Key = findRankData.Key
findResult.SortData = findRankData.SortData
findResult.RankPos = rankPos
}
return nil
}
// RPC_FindRankDataListStartTo 按pos查找,start开始count个排行数据
func (rs *RankService) RPC_FindRankDataListStartTo(findInfo *rpc.FindRankDataListStartTo, findResult *rpc.RankDataList) error {
rankObj, ok := rs.mapRankSkip[findInfo.RankId]
if ok == false || rankObj == nil {
return fmt.Errorf("RPC_FindRankDataListStartTo[", findInfo.RankId, "] no this rank type")
}
findResult.RankDataCount = rankObj.GetRankLen()
return rankObj.GetRankDataFromToLimit(findInfo.StartPos, findInfo.Count, findResult)
}
func (rs *RankService) deleteRankList(delIdList []uint64) {
if rs.mapRankSkip == nil {
return
}
for _, id := range delIdList {
delete(rs.mapRankSkip, id)
}
}
func (rs *RankService) dealCfg() error {
mapDBServiceCfg, ok := rs.GetServiceCfg().(map[string]interface{})
if ok == false {
return nil
}
cfgList, okList := mapDBServiceCfg["SortCfg"].([]interface{})
if okList == false {
return fmt.Errorf("RankService SortCfg must be list")
}
for _, cfg := range cfgList {
mapCfg, okCfg := cfg.(map[string]interface{})
if okCfg == false {
return fmt.Errorf("RankService SortCfg data must be map or struct")
}
rankId, okId := mapCfg["RankID"].(float64)
if okId == false {
return fmt.Errorf("RankService SortCfg data must has RankID[number]")
}
level, _ := mapCfg["SkipListLevel"].(float64)
isDec, _ := mapCfg["IsDec"].(bool)
maxRank, _ := mapCfg["MaxRank"].(float64)
newSkip := NewRankSkip(isDec, transformLevel(int32(level)), uint64(maxRank))
rs.mapRankSkip[uint64(rankId)] = newSkip
}
return nil
}

View File

@@ -0,0 +1,262 @@
package rankservice
import (
"fmt"
"github.com/duanhf2012/origin/rpc"
"github.com/duanhf2012/origin/util/algorithms/skip"
)
type RankSkip struct {
rankId uint64 //排行榜ID
isDes bool //是否为降序 true降序 false升序
skipList *skip.SkipList //跳表
mapRankData map[uint64]*RankData //排行数据map
maxLen uint64 //排行数据长度
rankModule IRankModule
}
// NewRankSkip 创建排行榜
func NewRankSkip(isDes bool, level interface{}, maxLen uint64) *RankSkip {
ret := &RankSkip{}
ret.isDes = isDes
ret.skipList = skip.New(level)
ret.mapRankData = make(map[uint64]*RankData, 10240)
ret.maxLen = maxLen
return ret
}
func (rs *RankSkip) SetupRankModule(rankModule IRankModule) {
rs.rankModule = rankModule
}
// GetRankID 获取排行榜Id
func (rs *RankSkip) GetRankID() uint64 {
return rs.rankId
}
// GetRankLen 获取排行榜长度
func (rs *RankSkip) GetRankLen() uint64 {
return rs.skipList.Len()
}
func (rs *RankSkip) UpsetRank(upsetRankData []*rpc.RankData) (addCount int32, modifyCount int32) {
addList := make([]*RankData, 0, 1)
updateList := make([]*RankData, 0, 1)
for _, upsetData := range upsetRankData {
changeData, changeType := rs.upsetRank(upsetData)
if changeData == nil {
continue
}
switch changeType {
case RankDataAdd:
addList = append(addList, changeData)
case RankDataUpdate:
updateList = append(updateList, changeData)
}
}
if len(addList) > 0 {
rs.rankModule.OnEnterRank(rs, addList)
}
if len(updateList) > 0 {
rs.rankModule.OnChangeRankData(rs, updateList)
}
addCount = int32(len(addList))
modifyCount = int32(len(updateList))
return
}
// UpsetRank 更新玩家排行数据,返回变化后的数据及变化类型
func (rs *RankSkip) upsetRank(upsetData *rpc.RankData) (*RankData, RankDataChangeType) {
rankNode, ok := rs.mapRankData[upsetData.Key]
if ok == true {
//找到的情况对比排名数据是否有变化,无变化进行data更新,有变化则进行删除更新
if compareIsEqual(rankNode.SortData, upsetData.SortData) {
rankNode.Data = upsetData.GetData()
return nil, RankDataNone
}
if upsetData.Data == nil {
upsetData.Data = rankNode.Data
}
rs.skipList.Delete(rankNode)
ReleaseRankData(rankNode)
newRankData := NewRankData(rs.isDes, upsetData)
rs.skipList.Insert(newRankData)
rs.mapRankData[upsetData.Key] = newRankData
return newRankData, RankDataUpdate
}
if rs.checkCanInsert(upsetData) {
newRankData := NewRankData(rs.isDes, upsetData)
rs.skipList.Insert(newRankData)
rs.mapRankData[upsetData.Key] = newRankData
return newRankData, RankDataAdd
}
return nil, RankDataNone
}
// DeleteRankData 删除排行数据
func (rs *RankSkip) DeleteRankData(delKeys []uint64) int32 {
removeRankData := make([]*RankData, 0, 1)
//预统计处理,进行回调
for _, key := range delKeys {
rankData, ok := rs.mapRankData[key]
if ok == false {
continue
}
removeRankData = append(removeRankData, rankData)
}
rs.rankModule.OnLeaveRank(rs, removeRankData)
//从排行榜中删除
for _, rankData := range removeRankData {
rs.skipList.Delete(rankData)
ReleaseRankData(rankData)
delete(rs.mapRankData, rankData.Key)
}
return int32(len(removeRankData))
}
// GetRankNodeData 获取,返回排名节点与名次
func (rs *RankSkip) GetRankNodeData(findKey uint64) (*RankData, uint64) {
rankNode, ok := rs.mapRankData[findKey]
if ok == false {
return nil, 0
}
_, index := rs.skipList.GetWithPosition(rankNode)
return rankNode, index
}
// GetRankNodeDataByPos 获取,返回排名节点与名次
func (rs *RankSkip) GetRankNodeDataByPos(pos uint64) (*RankData, uint64) {
rankNode := rs.skipList.ByPosition(pos)
if rankNode == nil {
return nil, 0
}
return rankNode.(*RankData), pos
}
// 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,
RankPos: rankPos - iterCount,
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,
RankPos: rankPos + iterCount,
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 fmt.Errorf("rank[", rs.rankId, "] no data")
}
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,
RankPos: iterCount + startPos,
SortData: rankData.SortData,
Data: rankData.Data,
})
iterCount++
}
return nil
}
// checkCanInsert 检查是否能插入
func (rs *RankSkip) checkCanInsert(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.rankModule.OnLeaveRank(rs, []*RankData{lastRankData})
rs.skipList.Delete(lastPosData)
delete(rs.mapRankData, lastRankData.Key)
ReleaseRankData(lastRankData)
return true
}

View File

@@ -0,0 +1,76 @@
syntax = "proto3";
package rpc;
option go_package = ".;rpc";
// RankData 排行数据
message RankData {
uint64 Key = 1; //数据主建
repeated int64 SortData = 2; //参与排行的数据
bytes Data = 3; //不参与排行的数据
int64 expireMs = 4; //剩余有效时间毫秒如果为0永不过期
}
// RankPosData 排行数据——查询返回
message RankPosData {
uint64 Key = 1; //数据主建
uint64 RankPos = 2; //名次
repeated int64 SortData = 3; //参与排行的数据
bytes Data = 4; //不参与排行的数据
}
// RankList 排行榜数据
message RankList {
uint64 RankId = 1; //排行榜类型
int32 SkipListLevel = 2; //排行榜level-生成的跳表的level, 8/16/32/64等
bool IsDec = 3; //不参与排行的数据
uint64 MaxRank = 4; //最大排名
}
// UpsetRankData 更新排行榜数据
message UpsetRankData {
uint64 RankId = 1; //排行榜的ID
repeated RankData RankDataList = 2; //排行数据
}
// DeleteByKey 更新排行榜数据
message DeleteByKey {
uint64 RankId = 1; //排行榜的分类ID
repeated uint64 KeyList = 2; //排行数据
}
// AddRankList 新增排行榜
message AddRankList {
repeated RankList AddList = 1; //添加的排行榜列表
}
// FindRankDataByKey 查找排行信息
message FindRankDataByKey {
uint64 RankId = 1; //排行榜的ID
uint64 Key = 2; //排行的key
}
// FindRankDataByPos 查找排行信息
message FindRankDataByPos {
uint64 RankId = 1; //排行榜的ID
uint64 Pos = 2; //排行名次
}
// FindRankDataListStartTo 查找排行信息,StartPos开始Count个
message FindRankDataListStartTo {
uint64 RankId = 1; //排行榜的ID
uint64 StartPos = 2; //排行的位置 0开始
uint64 Count = 3; //查询格式
}
// RankDataList
message RankDataList {
uint64 RankDataCount = 1; //排行长度
repeated RankPosData RankPosDataList = 2; //排行数据
}
// RankResult
message RankResult {
int32 AddCount = 1; //增加记录
int32 RemoveCount = 2; //删除数量
int32 ModifyCount = 3; //修改数量
}