goserver_sync/mmo/gatesrv/bundlemgr.go

265 lines
6.2 KiB
Go

package main
import (
"fmt"
"math"
"sync/atomic"
"time"
"mongo.games.com/goserver/core/module"
"mongo.games.com/goserver/core/netlib"
"mongo.games.com/goserver/srvlib"
)
var (
SessionHandlerBundleName = "handler-client-bundle"
BundleMgrSington = &BundleMgr{}
)
type SendPendItem struct {
sid int //当前pending包发给的session
packetid int
logicNo uint32
data interface{}
ts int64
}
type BundleSession struct {
bundleKey string
bundleSession []*netlib.Session
currentSession *netlib.Session
fastestSession *netlib.Session
worldsrvSession *netlib.Session
gamesrvSession *netlib.Session
waitAckChain []*SendPendItem
rcvLogicNo uint32
sndLogicNo uint32
lastSndTs int64
lastAckTs int64
RTT int64 //Round Trip Time
RTO int64 //Retransmission TimeOut
}
func (bs *BundleSession) OnSessionClose(s *netlib.Session) bool {
if bs.fastestSession == s {
bs.fastestSession = nil
}
if bs.currentSession == s {
bs.currentSession = nil
}
cnt := len(bs.bundleSession)
for i := 0; i < cnt; i++ {
if bs.bundleSession[i] == s {
if i == 0 {
bs.bundleSession = bs.bundleSession[1:]
} else if i == cnt-1 {
bs.bundleSession = bs.bundleSession[:cnt-1]
} else {
temp := bs.bundleSession[:i]
temp = append(temp, bs.bundleSession[i+1:]...)
bs.bundleSession = temp
}
break
}
}
//优先最快的一个连接
if bs.currentSession == nil {
bs.currentSession = bs.fastestSession
}
//从池里面挑选一个
if bs.currentSession == nil {
if len(bs.bundleSession) > 0 {
bs.currentSession = bs.bundleSession[0]
}
}
//重发没有回应的包
if bs.currentSession != nil {
idx := -1
for i, pack := range bs.waitAckChain {
if pack.sid == s.Id {
bs.currentSession.SendEx(pack.packetid, pack.logicNo, pack.data, false)
idx = i
} else {
break
}
}
if idx != -1 {
if idx < len(bs.waitAckChain) {
bs.waitAckChain = bs.waitAckChain[idx+1:]
}
}
} else { //所有连接都已关闭
return true
}
return false
}
func (bs *BundleSession) CacheSendItem(sid, packetid int, logicNo uint32, data interface{}) {
ts := module.AppModule.GetCurrTimeNano()
bs.waitAckChain = append(bs.waitAckChain, &SendPendItem{
sid: sid,
packetid: packetid,
logicNo: logicNo,
data: data,
ts: ts,
})
bs.lastSndTs = ts
}
func (bs *BundleSession) Send(packetid int, pack interface{}) {
if bs.currentSession != nil {
logicNo := atomic.AddUint32(&bs.sndLogicNo, 1)
if bs.currentSession.SendEx(packetid, logicNo, pack, false) {
bs.CacheSendItem(bs.currentSession.Id, packetid, logicNo, pack)
}
}
}
type BundleMgr struct {
freeBundle []uint16
bundles [math.MaxUint16]*BundleSession
bundlesMap map[string]uint16
Debug bool
}
// 主线程中调用
func (bm *BundleMgr) AllocBundleId() uint16 {
last := len(bm.freeBundle)
if last > 0 {
id := bm.freeBundle[last-1]
bm.freeBundle = bm.freeBundle[:last-1]
return id
}
return 0
}
// 主线程中调用
func (bm *BundleMgr) FreeBundleId(id uint16) {
if bm.Debug {
for i := 0; i < len(bm.freeBundle); i++ {
if bm.freeBundle[i] == id {
panic(fmt.Sprintf("BundleMgr.FreeBundleId found repeat id:%v", id))
}
}
}
bm.freeBundle = append(bm.freeBundle, id)
delete(bm.bundlesMap, bm.bundles[id].bundleKey)
bm.bundles[id] = nil
}
// 主线程中调用
func (bm *BundleMgr) BindSession(bundleId uint16, s *netlib.Session) {
if bm.bundles[bundleId] == nil {
bm.bundles[bundleId] = &BundleSession{
RTO: int64(time.Second),
}
}
bs := bm.bundles[bundleId]
if bs != nil {
s.GroupId = int(bundleId)
param := s.GetAttribute(srvlib.SessionAttributeClientSession)
if param != nil {
if sid, ok := param.(srvlib.SessionId); ok {
s.Sid = int64(srvlib.NewSessionIdEx(int32(sid.AreaId()), int32(sid.SrvType()), int32(sid.SrvId()), int32(bundleId)))
}
}
bs.bundleSession = append(bs.bundleSession, s)
if bs.fastestSession == nil {
bs.fastestSession = s
}
if bs.currentSession == nil {
bs.currentSession = s
}
}
}
func (bm *BundleMgr) GetBundleSession(bundleId uint16) *BundleSession {
return bm.bundles[bundleId]
}
// 主线程中调用
func (bm *BundleMgr) OnSessionAck(s *netlib.Session, logicNo uint32) {
if s != nil {
bs := bm.GetBundleSession(uint16(s.GroupId))
if bs != nil {
if len(bs.waitAckChain) > 0 && bs.waitAckChain[0].logicNo == logicNo {
pendingItem := bs.waitAckChain[0]
bs.waitAckChain = bs.waitAckChain[1:]
bs.fastestSession = s
if len(bs.waitAckChain) == 0 { //切换响应更快的链接
bs.currentSession = bs.fastestSession
}
bs.lastAckTs = module.AppModule.GetCurrTimeNano()
bs.RTT = bs.lastAckTs - pendingItem.ts
bs.RTO = bs.RTT * 5
if bs.RTO > int64(time.Second) { //最长1秒
bs.RTO = int64(time.Second)
}
}
}
}
}
func (bm *BundleMgr) Broadcast(packetid int, pack interface{}) {
for _, bid := range bm.bundlesMap {
bs := bm.GetBundleSession(bid)
if bs != nil {
bs.Send(packetid, pack)
}
}
}
func (bm *BundleMgr) ModuleName() string {
return "BundleMgr"
}
func (bm *BundleMgr) Init() {
bm.freeBundle = make([]uint16, 0, math.MaxUint16)
for i := uint16(math.MaxUint16); i > 0; i-- {
bm.freeBundle = append(bm.freeBundle, i)
}
bm.bundlesMap = make(map[string]uint16)
}
func (bm *BundleMgr) Update() {
ts := module.AppModule.GetCurrTimeNano()
for _, id := range bm.bundlesMap {
bs := bm.GetBundleSession(id)
if bs != nil {
if len(bs.waitAckChain) > 0 && ts-bs.waitAckChain[0].ts > bs.RTO { //重发
s := bs.fastestSession
if s == bs.currentSession {
for _, ss := range bs.bundleSession {
if s != ss {
s = ss
break
}
}
}
if s != bs.currentSession {
bs.currentSession = s
chain := bs.waitAckChain
bs.waitAckChain = nil
for _, item := range chain {
if ts-item.ts > bs.RTO {
if bs.currentSession.SendEx(item.packetid, item.logicNo, item.data, false) {
bs.CacheSendItem(bs.currentSession.Id, item.packetid, item.logicNo, item.data)
}
}
}
}
}
}
}
}
func (bm *BundleMgr) Shutdown() {
module.UnregisteModule(bm)
}
func init() {
module.RegisteModule(BundleMgrSington, time.Millisecond*100, 0)
}