|
|
@@ -9,6 +9,7 @@ local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
|
|
|
local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
|
|
|
local RoleDBLogic = require("role.RoleDBLogic")
|
|
|
local MailExcel = require("excel.mail")
|
|
|
+local CommonDB = require("common.CommonDB")
|
|
|
|
|
|
SYSTEM = 1 -- 系统邮件
|
|
|
GONGGAO = 2 -- 公告
|
|
|
@@ -75,7 +76,8 @@ function add(type,receiverUuid,title,content,items,senderName,sender,time,fbTime
|
|
|
mail.flag = 1
|
|
|
end
|
|
|
LuaMongo.insert(DB.db_mail, mail)
|
|
|
- RoleSystemLogic.onDotByUuid(receiverUuid, RoleSystemDefine.ROLE_SYS_ID_204)
|
|
|
+ -- 检测红点会调用getMails(), 短时间插入多封邮件加上玩家邮件数量过多,会发生段错误
|
|
|
+ -- RoleSystemLogic.onDotByUuid(receiverUuid, RoleSystemDefine.ROLE_SYS_ID_204)
|
|
|
return mail
|
|
|
|
|
|
end
|
|
|
@@ -156,45 +158,149 @@ local function cmpMail(a, b)
|
|
|
end
|
|
|
|
|
|
local mails = {}
|
|
|
-function getMails(receiverUuid,mailType)
|
|
|
- for key in ipairs(mails) do
|
|
|
- mails[key] = nil
|
|
|
- end
|
|
|
+-- function getMails(receiverUuid,mailType)
|
|
|
+-- for key in ipairs(mails) do
|
|
|
+-- mails[key] = nil
|
|
|
+-- end
|
|
|
+
|
|
|
+-- FIELD_RECEIVER.receiverUuid = receiverUuid
|
|
|
+-- FIELD_RECEIVER.type = mailType
|
|
|
+
|
|
|
+-- LuaMongo.find(DB.db_mail,{["$query"]=FIELD_RECEIVER})
|
|
|
+
|
|
|
+-- local lastTime = os.time() - 7 * 86400
|
|
|
+-- local mailCnt = 0
|
|
|
+-- while true do
|
|
|
+-- local mail = {}
|
|
|
+-- -- if not LuaMongo.next(mail) then
|
|
|
+-- -- break
|
|
|
+-- -- end
|
|
|
|
|
|
- FIELD_RECEIVER.receiverUuid = receiverUuid
|
|
|
- FIELD_RECEIVER.type = mailType
|
|
|
+-- local res, err = pcall(function ()
|
|
|
+-- return LuaMongo.next(mail)
|
|
|
+-- end)
|
|
|
|
|
|
- LuaMongo.find(DB.db_mail,{["$query"]=FIELD_RECEIVER})
|
|
|
+-- if not res then
|
|
|
+-- Log.write(Log.LOGID_DEBUG, "MailManager.getMails err = ".. err)
|
|
|
+-- break
|
|
|
+-- end
|
|
|
+
|
|
|
+-- if not err then
|
|
|
+-- break
|
|
|
+-- end
|
|
|
+
|
|
|
+-- if mail.expireTime then -- 有指定过期时间
|
|
|
+-- if mail.time > os.time() - mail.expireTime then
|
|
|
+-- mailCnt = mailCnt + 1
|
|
|
+-- mails[mailCnt] = mail
|
|
|
+-- end
|
|
|
+-- elseif mail.time > lastTime then -- 没有就用默认过期时间
|
|
|
+-- mailCnt = mailCnt + 1
|
|
|
+-- mails[mailCnt] = mail
|
|
|
+-- end
|
|
|
+-- end
|
|
|
|
|
|
- local lastTime = os.time() - 7 * 86400
|
|
|
+-- if mailCnt > MAIL_MAX_CNT then
|
|
|
+-- table.sort(mails, cmpMail)
|
|
|
+-- for i = MAIL_MAX_CNT + 1, mailCnt do
|
|
|
+-- mails[i] = nil
|
|
|
+-- end
|
|
|
+-- end
|
|
|
+-- return mails
|
|
|
+-- end
|
|
|
+
|
|
|
+-- 替换原有的 getMails 函数
|
|
|
+function getMails(receiverUuid, mailType)
|
|
|
+ -- 1. 清空缓存表
|
|
|
+ for i = 1, #mails do mails[i] = nil end
|
|
|
+
|
|
|
+ local now = os.time()
|
|
|
local mailCnt = 0
|
|
|
- while true do
|
|
|
- local mail = {}
|
|
|
- if not LuaMongo.next(mail) then
|
|
|
- break
|
|
|
- end
|
|
|
+ local tempMails = {}
|
|
|
+ local SCAN_LIMIT = 2000 -- 单次分段查询安全上限
|
|
|
+ local foundEnough = false
|
|
|
+
|
|
|
+ -- 2.将时间划分为多个小窗口,避免单次 find 触发底层 OOM
|
|
|
+ -- 窗口设计:最近7天 -> 7~14天 -> 14~30天 -> 30~60天
|
|
|
+ local timeWindows = {
|
|
|
+ {now - 7*86400, now},
|
|
|
+ {now - 14*86400, now - 7*86400},
|
|
|
+ {now - 30*86400, now - 14*86400},
|
|
|
+ {now - 60*86400, now - 30*86400}
|
|
|
+ }
|
|
|
+ -- 60天 -> 开服
|
|
|
+ local serverOpenTime = CommonDB.getServerOpenTime()
|
|
|
+ timeWindows[#timeWindows+1] = { serverOpenTime, now - 60*86400 }
|
|
|
+
|
|
|
+ for _, window in ipairs(timeWindows) do
|
|
|
+ if foundEnough then break end
|
|
|
+
|
|
|
+ -- 使用最简平铺查询,彻底避开 C 扩展解析缺陷
|
|
|
+ local query = {
|
|
|
+ receiverUuid = receiverUuid,
|
|
|
+ type = mailType,
|
|
|
+ time = { ["$gte"] = window[1], ["$lte"] = window[2] }
|
|
|
+ }
|
|
|
|
|
|
- if mail.expireTime then -- 有指定过期时间
|
|
|
- if mail.time > os.time() - mail.expireTime then
|
|
|
- mailCnt = mailCnt + 1
|
|
|
- mails[mailCnt] = mail
|
|
|
+ LuaMongo.find(DB.db_mail, query)
|
|
|
+
|
|
|
+ local mail = {}
|
|
|
+ local scanCnt = 0
|
|
|
+ while true do
|
|
|
+ local has_next = LuaMongo.next(mail)
|
|
|
+ if not has_next then break end
|
|
|
+
|
|
|
+ scanCnt = scanCnt + 1
|
|
|
+ if scanCnt > SCAN_LIMIT then
|
|
|
+ Log.write(Log.LOGID_DEBUG, string.format("Mail segment limit hit! uuid=%s window=%d~%d",
|
|
|
+ receiverUuid, window[1], window[2]))
|
|
|
+ break
|
|
|
end
|
|
|
- elseif mail.time > lastTime then -- 没有就用默认过期时间
|
|
|
+
|
|
|
+ -- 浅拷贝隔离 C 驱动内部 Buffer
|
|
|
+ local m = {}
|
|
|
+ for k, v in pairs(mail) do m[k] = v end
|
|
|
+ tempMails[#tempMails + 1] = m
|
|
|
+
|
|
|
+ -- 清空复用表
|
|
|
+ for k in pairs(mail) do mail[k] = nil end
|
|
|
+ end
|
|
|
+
|
|
|
+ -- 如果已收集足够多数据(留足过滤冗余),提前终止后续窗口查询
|
|
|
+ if #tempMails >= 500 then
|
|
|
+ foundEnough = true
|
|
|
+ break
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ -- 3.按时间倒序排序,确保后续取到的是“最新”的
|
|
|
+ table.sort(tempMails, cmpMail)
|
|
|
+
|
|
|
+ -- 4. 过滤过期邮件,精准截取最新 100 条
|
|
|
+ for _, m in ipairs(tempMails) do
|
|
|
+ if type(m.time) ~= "number" then m.time = 0 end
|
|
|
+
|
|
|
+ local isExpired = false
|
|
|
+ local expireTime = m.expireTime
|
|
|
+ if expireTime and type(expireTime) == "number" then
|
|
|
+ if m.time <= now - expireTime then isExpired = true end
|
|
|
+ elseif m.time <= now - 7 * 86400 then
|
|
|
+ isExpired = true
|
|
|
+ end
|
|
|
+
|
|
|
+ if not isExpired then
|
|
|
mailCnt = mailCnt + 1
|
|
|
- mails[mailCnt] = mail
|
|
|
- end
|
|
|
- end
|
|
|
-
|
|
|
- if mailCnt > MAIL_MAX_CNT then
|
|
|
- table.sort(mails, cmpMail)
|
|
|
- for i = MAIL_MAX_CNT + 1, mailCnt do
|
|
|
- mails[i] = nil
|
|
|
- end
|
|
|
- end
|
|
|
- return mails
|
|
|
+ mails[mailCnt] = m
|
|
|
+ if mailCnt >= MAIL_MAX_CNT then break end -- 达到 100 条立即退出
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ return mails
|
|
|
end
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
function saveMail(mail)
|
|
|
FIELD_ID._id = mail._id
|
|
|
LuaMongo.update(DB.db_mail, FIELD_ID, mail)
|