From 4087d18ce7cbd1578a6e287962bd902386984048 Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期一, 14 七月 2025 10:55:57 +0800 Subject: [PATCH] Merge branch 'master' of http://192.168.1.20:10010/r/Project_SG_ServerCode --- ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py | 152 ++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 116 insertions(+), 36 deletions(-) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py index f5ea998..99dc267 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py @@ -16,11 +16,16 @@ #------------------------------------------------------------------------------- import CommFunc +import DBStruct +import ChConfig import GameWorld import PyGameData -import DBEventTrig +import PyMongoMain import DBPlayerViewCache +import DBEventTrig import DBBillboard +import DBFuncTeam +import DBGameRec import DBFamily import DBMail @@ -28,43 +33,56 @@ import os BakRoot = "C:\ServerRealTimeBackup" -BakFileType = ".bak" -BackupCopyMax = 3 +BakFileType = ".rtb" +BackupCopyMax = 5 # 保留历史备档文件数 +BackupInterval = 30 # 备档频率,分钟,暂定每30分钟 -g_loadErr = False - def OnServerStart(): + ##启动服务器数据处理 GameWorld.DebugLog("地图服务器启动") - LoadServerDataBackup() + if not LoadGameWorldDataFromBackup(): + LoadGameWorldDataFromDB() return def OnServerClose(): + ##关服服务器数据处理 + SaveGameWorldDataToDB() return def OnMinute(curTime): - #curMinute = curTime.minute - ServerDataBackup() + if PyGameData.g_serverClosing: + return DBFamily.OnMinute() DBBillboard.OnMinute() + + #备档、入库放最后,等数据都处理完后再保存,每天 [[时,分], ...],尽量岔开整点、5分 + if [curTime.hour, curTime.minute] in [[3, 6]]: + BackupGameWorldData(True) + else: + BackupGameWorldData(False) return #------------------------------------------- 备档 --------------------------------------------------- def GetBakFileSortList(bakPath): - ## 按备档时间倒序排序返回 [[bakTime, filePath], ...] + ## 按备档时间倒序排序返回 [[bakTime, 数据版本号, filePath], ...] bakFileList = [] for parent, _, filenames in os.walk(bakPath): for filename in filenames: if not filename.endswith(BakFileType): continue fullPath = os.path.join(parent, filename) - bakTime = GameWorld.ToIntDef(filename[:filename.index(".")].split("_")[1]) - bakFileList.append([bakTime, fullPath]) + bakInfo = filename[:filename.index(".")].split("_") + if len(bakInfo) != 3: + continue + dataVersionNO = GameWorld.ToIntDef(bakInfo[1]) # 数据版本号 + bakTime = GameWorld.ToIntDef(bakInfo[2]) # yyyyMMddhhmmss + bakFileList.append([bakTime, dataVersionNO, fullPath]) bakFileList.sort(reverse=True) return bakFileList -def LoadServerDataBackup(): - ## 服务器公共数据备档加载 - global g_loadErr +def LoadGameWorldDataFromBackup(): + ## 备档加载服务器公共数据 + # @return: 是否存在备档成功加载 serverID = GameWorld.GetGameWorld().GetServerID() serverName = "S%s" % serverID BakDir = os.path.join(BakRoot, serverName) @@ -73,26 +91,42 @@ if not bakFileList: GameWorld.Log("不存在备档!") return - bakFilePath = bakFileList[0][1] # 取第一个为最近的一次备档 + finalBakInfo = bakFileList[0] # 排序后的第一个为最新备档数据 + bakVersionNO = finalBakInfo[1] + bakFilePath = finalBakInfo[2] + if bakVersionNO != DBStruct.GAMEWORLD_DATA_VERSION_NO: + GameWorld.ErrLog("备档数据版本号校验失败,请使用正确版本服务器启动重新导入数据! bakVersionNO=%s, GAMEWORLD_DATA_VERSION_NO=%s" + % (bakVersionNO, DBStruct.GAMEWORLD_DATA_VERSION_NO)) + raise + GameWorld.Log("读取备档: %s" % bakFilePath) f = open(bakFilePath, 'rb') compressed_data = f.read() f.close() - bakData = CommFunc.Decompress(compressed_data) - if not bakData: - g_loadErr = True - raise + saveData = CommFunc.Decompress(compressed_data) + if not saveData: + raise - LoadPyGameData(bakData, 0) - return + LoadPyGameData(saveData, 0) + SaveGameWorldDataToDB(saveData) # 如果是从备档读取的则直接入库 + return True -def ServerDataBackup(): +def BackupGameWorldData(saveToDB=False): ## 服务器公共数据定时备档,暂时直接存盘 - if g_loadErr: - GameWorld.ErrLog("加载备档已异常,暂时不再存储备档,防止已经错误加载的数据覆盖") + # @param saveToDB: 是否附带入库,为确保备档数据存在时一定优于db库数据,故常规入库时必须附带先备档一次 + if PyGameData.g_serverClosing: return + if not PyGameData.g_loadDataOK: + GameWorld.Log("加载数据未完成,不存储备档") + return + curTime = int(time.time()) + if saveToDB: + if curTime - PyGameData.g_lastRTBTime < BackupInterval * 60: + GameWorld.Log("备档冷却中!") + return + serverID = GameWorld.GetGameWorld().GetServerID() serverName = "S%s" % serverID BakDir = os.path.join(BakRoot, serverName) @@ -101,11 +135,12 @@ if not os.path.exists(BakDir): os.makedirs(BakDir) - curTime = int(time.time()) - bakFilePath = os.path.join(BakDir, "%s_%s%s" % (serverName, curTime, BakFileType)) - bakData = GetSavePyData() - GameWorld.Log("Bak:%s, len=%s, %s" % (serverName, len(bakData), bakFilePath)) - compressed_data = CommFunc.Compress(bakData) + dataVersionNO = DBStruct.GAMEWORLD_DATA_VERSION_NO + bakTiemStr = GameWorld.ChangeTimeNumToStr(curTime, ChConfig.TYPE_Time_Format_YmdHMS) + bakFilePath = os.path.join(BakDir, "%s_%s_%s%s" % (serverName, dataVersionNO, bakTiemStr, BakFileType)) + saveData = GetSavePyData() + GameWorld.Log("Bak:%s, len=%s, %s" % (serverName, len(saveData), bakFilePath)) + compressed_data = CommFunc.Compress(saveData) # 备档数据才进行压缩 if not compressed_data: GameWorld.SendGameError("ServerDataBackupError") return @@ -118,15 +153,42 @@ except: return + PyGameData.g_lastRTBTime = curTime bakFileList = GetBakFileSortList(BakDir) # 删除多余备档 - for _, filePath in bakFileList[BackupCopyMax:]: + for bakInfo in bakFileList[BackupCopyMax:]: + filePath = bakInfo[-1] os.remove(filePath) GameWorld.Log("删除多余备档文件: %s" % filePath) + if saveToDB: + SaveGameWorldDataToDB(saveData) + return + +def ClearBackupFile(): + ## 清空备档文件 + serverID = GameWorld.GetGameWorld().GetServerID() + serverName = "S%s" % serverID + BakDir = os.path.join(BakRoot, serverName) + GameWorld.Log("清空备档: %s" % BakDir) + CommFunc.DelFolder(BakDir, True) return #-------------------------------------------------------------------------------------------------- + +def LoadGameWorldDataFromDB(): + ## 直接从db读取公共数据 + GameWorld.Log("没有备档数据,直接从db加载数据!") + serverData = PyMongoMain.GetUserCtrlDB().readGameWorldData() + LoadPyGameData(serverData, 0) + return + +def SaveGameWorldDataToDB(saveData=""): + ## 公共数据入库 + if not saveData: + saveData = GetSavePyData() + PyMongoMain.GetUserCtrlDB().saveGameWorldData(saveData) + return def GetSavePyData(): @@ -146,33 +208,42 @@ #加载数据后,一些功能转化为功能业务数据 #... + + #放最后 + PyGameData.g_loadDataOK = True return pos class PyGameDataManager(object): def __init__(self): self.EventTrigMgr = DBEventTrig.EventTrigMgr() self.PlayerViewCacheMgr = DBPlayerViewCache.PlayerViewCacheMgr() - self.FamilyMgr = DBFamily.FamilyMgr() - self.MailMgr = DBMail.MailMgr() self.BillboardMgr = DBBillboard.BillboardMgr() + self.MailMgr = DBMail.MailMgr() + self.FamilyMgr = DBFamily.FamilyMgr() + self.GameRecMgr = DBGameRec.GameRecMgr() + self.FuncTeamMgr = DBFuncTeam.FuncTeamMgr() return def GetSaveData(self): buff = "" buff += self.EventTrigMgr.GetSaveData() buff += self.PlayerViewCacheMgr.GetSaveData() - buff += self.FamilyMgr.GetSaveData() - buff += self.MailMgr.GetSaveData() buff += self.BillboardMgr.GetSaveData() + buff += self.MailMgr.GetSaveData() + buff += self.FamilyMgr.GetSaveData() + buff += self.GameRecMgr.GetSaveData() + buff += self.FuncTeamMgr.GetSaveData() return buff def LoadGameData(self, gameBuffer, pos): dataslen = len(gameBuffer) pos = self.EventTrigMgr.LoadPyGameData(gameBuffer, pos, dataslen) pos = self.PlayerViewCacheMgr.LoadPyGameData(gameBuffer, pos, dataslen) - pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, dataslen) - pos = self.MailMgr.LoadPyGameData(gameBuffer, pos, dataslen) pos = self.BillboardMgr.LoadPyGameData(gameBuffer, pos, dataslen) + pos = self.MailMgr.LoadPyGameData(gameBuffer, pos, dataslen) + pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, dataslen) + pos = self.GameRecMgr.LoadPyGameData(gameBuffer, pos, dataslen) + pos = self.FuncTeamMgr.LoadPyGameData(gameBuffer, pos, dataslen) return pos def GetDBDataMgr(): @@ -212,3 +283,12 @@ dbDataMgr = GetDBDataMgr() return dbDataMgr.BillboardMgr +def GetGameRecMgr(): + ## 通用记录数据管理器 + dbDataMgr = GetDBDataMgr() + return dbDataMgr.GameRecMgr + +def GetFuncTeamMgr(): + ## 功能队伍数据管理器 + dbDataMgr = GetDBDataMgr() + return dbDataMgr.FuncTeamMgr -- Gitblit v1.8.0