[10970] Implement mass mail send infrastructure.

It expected to be used in 2 case: some gameevent must send mails at start/end,
and this can be useful in game commands. Both case wil implemented in later commits.

* New MassMailMgr can accept tasks for send mass mails in safe way for map update threads context/etc.
* It work in way:
   - By provided race mask or more generic SQL query string in async query selected affected characters
   - At query result ready at next world tick update in safe common part of tick code some from mails
     from queued mas mail tasks send.
   - Amount mails limited MassMailer.SendPerTick confir option (10 by default). This done for prevent
     high server load/lags at send too many mails in one tick (mail send all existed characters in DB
     who match to seelction criteria)
   - Manager not persistant for server shutdowns so any not send mails in queue lost at shutdown.
     But with default setting 10K mail send in 20 secs (10000/50/10). Adding more safe execution
     for this case will make related code lot more slow and req. many DB tables and code support.
This commit is contained in:
VladimirMangos 2011-01-06 05:48:35 +03:00
parent 231c6d77ce
commit 5f2aef756a
13 changed files with 331 additions and 2 deletions

View file

@ -918,6 +918,33 @@ void MailDraft::deleteIncludedItems( bool inDB /**= false*/ )
m_items.clear(); m_items.clear();
} }
/**
* Clone MailDraft from another MailDraft.
*
* @param draft Point to source for draft cloning.
*/
void MailDraft::CloneFrom(MailDraft const& draft)
{
m_mailTemplateId = draft.GetMailTemplateId();
m_mailTemplateItemsNeed = draft.m_mailTemplateItemsNeed;
m_subject = draft.GetSubject();
m_body = draft.GetBody();
m_money = draft.GetMoney();
m_COD = draft.GetCOD();
for(MailItemMap::const_iterator mailItemIter = draft.m_items.begin(); mailItemIter != draft.m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
if(Item* newitem = item->CloneItem(item->GetCount()))
{
newitem->SaveToDB();
AddItem(newitem);
}
}
}
/* /*
* Returns a mail to its sender. * Returns a mail to its sender.
* @param sender_acc The id of the account of the sender. * @param sender_acc The id of the account of the sender.

View file

@ -18,9 +18,11 @@
/** /**
* @addtogroup mailing The mail system * @addtogroup mailing The mail system
* The mailing system in MaNGOS consists of mostly two files: * The mailing system in MaNGOS consists of mostly 4 files:
* - Mail.h * - Mail.h
* - Mail.cpp * - Mail.cpp
* - MassMailMgr.h
* - MassMailMgr.cpp
* *
* @{ * @{
* *
@ -237,6 +239,8 @@ class MailDraft
* @param COD the amount to which the cod should be set. * @param COD the amount to which the cod should be set.
*/ */
MailDraft& SetCOD(uint32 COD) { m_COD = COD; return *this; } MailDraft& SetCOD(uint32 COD) { m_COD = COD; return *this; }
void CloneFrom(MailDraft const& draft);
public: // finishers public: // finishers
void SendReturnToSender(uint32 sender_acc, ObjectGuid sender_guid, ObjectGuid receiver_guid); void SendReturnToSender(uint32 sender_acc, ObjectGuid sender_guid, ObjectGuid receiver_guid);
void SendMailTo(MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0); void SendMailTo(MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0);

View file

@ -183,6 +183,8 @@ libmangosgame_a_SOURCES = \
MapManager.h \ MapManager.h \
MapReference.h \ MapReference.h \
MapRefManager.h \ MapRefManager.h \
MassMailMgr.cpp \
MassMailMgr.h \
MiscHandler.cpp \ MiscHandler.cpp \
MotionMaster.cpp \ MotionMaster.cpp \
MotionMaster.h \ MotionMaster.h \

134
src/game/MassMailMgr.cpp Normal file
View file

@ -0,0 +1,134 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @addtogroup mailing
* @{
*
* @file MassMailMgr.cpp
* This file contains the the code needed for MaNGOS to handle mass mails send in safe and perfomence not affecting way.
*
*/
#include "MassMailMgr.h"
#include "Policies/SingletonImp.h"
#include "Database/DatabaseEnv.h"
#include "Database/DatabaseImpl.h"
#include "SharedDefines.h"
#include "World.h"
#include "ObjectMgr.h"
INSTANTIATE_SINGLETON_1(MassMailMgr);
void MassMailMgr::AddMassMailTask(MailDraft* mailProto, MailSender sender, uint32 raceMask)
{
if (RACEMASK_ALL_PLAYABLE & ~raceMask) // have races not included in mask
{
std::ostringstream ss;
ss << "SELECT guid FROM characters WHERE (1 << (race - 1)) & " << raceMask << " AND deleteDate IS NULL";
AddMassMailTask(mailProto, sender, ss.str().c_str());
}
else
AddMassMailTask(mailProto, sender, "SELECT guid FROM characters WHERE deleteDate IS NULL");
}
struct MassMailerQueryHandler
{
void HandleQueryCallback(QueryResult * result, MailDraft* mailProto, MailSender sender)
{
if (!result)
return;
MassMailMgr::ReceiversList& recievers = sMassMailMgr.AddMassMailTask(mailProto, sender);
do
{
Field *fields = result->Fetch();
recievers.insert(fields[0].GetUInt32());
} while (result->NextRow());
delete result;
}
} massMailerQueryHandler;
void MassMailMgr::AddMassMailTask(MailDraft* mailProto, MailSender sender, char const* query)
{
CharacterDatabase.AsyncPQuery(&massMailerQueryHandler, &MassMailerQueryHandler::HandleQueryCallback, mailProto, sender, query);
}
void MassMailMgr::Update()
{
if (m_massMails.empty())
return;
uint32 maxcount = sWorld.getConfig(CONFIG_UINT32_MASS_MAILER_SEND_PER_TICK);
do
{
MassMail& task = m_massMails.front();
while (!task.m_recivers.empty() && maxcount > 0)
{
uint32 receiver_lowguid = *task.m_recivers.begin();
task.m_recivers.erase(task.m_recivers.begin());
ObjectGuid receiver_guid = ObjectGuid(HIGHGUID_PLAYER, receiver_lowguid);
Player *receiver = sObjectMgr.GetPlayer(receiver_guid);
// last case. can be just send
if (task.m_recivers.empty())
{
// prevent mail return
task.m_protoMail->SendMailTo(MailReceiver(receiver, receiver_guid), task.m_sender, MAIL_CHECK_MASK_RETURNED);
--maxcount;
break;
}
// need clone draft
MailDraft draft;
draft.CloneFrom(*task.m_protoMail);
// prevent mail return
draft.SendMailTo(MailReceiver(receiver, receiver_guid), task.m_sender, MAIL_CHECK_MASK_RETURNED);
--maxcount;
}
if (task.m_recivers.empty())
m_massMails.pop_front();
}
while(!m_massMails.empty() && maxcount > 0);
}
void MassMailMgr::GetStatistic(uint32& tasks, uint32& mails, uint32& needTime) const
{
tasks = m_massMails.size();
uint32 mailsCount = 0;
for (MassMailList::const_iterator mailItr = m_massMails.begin(); mailItr != m_massMails.end(); ++mailItr)
mailsCount += mailItr->m_recivers.size();
mails = mailsCount;
// 50 msecs is tick length
needTime = 50 * mailsCount / sWorld.getConfig(CONFIG_UINT32_MASS_MAILER_SEND_PER_TICK) / IN_MILLISECONDS;
}
/*! @} */

125
src/game/MassMailMgr.h Normal file
View file

@ -0,0 +1,125 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @addtogroup mailing The mail system
* The mailing system in MaNGOS consists of mostly 4 files:
* - Mail.h
* - Mail.cpp
* - MassMailMgr.h
* - MassMailMgr.cpp
*
* @{
*
* @file MassMailMgr.h
* This file contains the the headers needed for MaNGOS to handle mass mails send in safe and perfomence not affecting way.
*
*/
#ifndef MANGOS_MASS_MAIL_MGR_H
#define MANGOS_MASS_MAIL_MGR_H
#include "Common.h"
#include "Mail.h"
#include "Policies/Singleton.h"
#include <memory>
/**
* A class to represent the mail send factory to multiply (often all existed) characters.
*
* Note: implementation not persistence for server shutdowns
*/
class MassMailMgr
{
public: // Constructors
MassMailMgr() {}
public: // Accessors
void GetStatistic(uint32& tasks, uint32& mails, uint32& needTime) const;
public: // modifiers
typedef UNORDERED_SET<uint32> ReceiversList;
/**
* And new mass mail task for raceMask filter applied to characters list.
*
* @param mailProto prepared mail for clone and send to characters, will deleted in result call.
* @param raceMask mask of races that must receive mail.
*
* Note: this function safe to be called from Map::Update content/etc, real data add will executed in next tick after query resultrs ready
*/
void AddMassMailTask(MailDraft* mailProto, MailSender sender, uint32 raceMask);
/**
* And new mass mail task with SQL query text for fill receivers list.
*
* @param mailProto prepared mail for clone and send to characters, will deleted in result call
* @param queryStr SQL query for get guid list of receivers, first field in query result must be uint32 low guids list.
*
* Note: this function safe to be called from Map::Update content/etc, real data add will executed in next tick after query resultrs ready
*/
void AddMassMailTask(MailDraft* mailProto, MailSender sender, char const* queryStr);
/**
* And new mass mail task and let fill receivers list returned as result.
*
* @param mailProto prepared mail for clone and send to characters, will deleted in result call
* @returns reference to receivers list for it fill in caller code.
*
* Note: this function NOT SAFE for call from Map::Update content/etc
*/
ReceiversList& AddMassMailTask(MailDraft* mailProto, MailSender sender)
{
m_massMails.push_back(MassMail(mailProto, sender));
return m_massMails.rbegin()->m_recivers;
}
/**
* Next step in mass mail activity, send some amount mails from queued tasks
*/
void Update();
private:
/// Mass mail task store mail prototype and receivers list who not get mail yet
struct MassMail
{
explicit MassMail(MailDraft* mailProto, MailSender sender)
: m_protoMail(mailProto), m_sender(sender)
{
MANGOS_ASSERT(mailProto);
}
/// m_protoMail is owned by MassMail, so at copy original MassMail field set to NULL
std::auto_ptr<MailDraft> m_protoMail;
MailSender m_sender;
ReceiversList m_recivers;
};
typedef std::list<MassMail> MassMailList;
/// List of current queued mass mail tasks
MassMailList m_massMails;
};
#define sMassMailMgr MaNGOS::Singleton<MassMailMgr>::Instance()
#endif
/*! @} */

View file

@ -42,6 +42,7 @@
#include "SpellMgr.h" #include "SpellMgr.h"
#include "Chat.h" #include "Chat.h"
#include "DBCStores.h" #include "DBCStores.h"
#include "MassMailMgr.h"
#include "LootMgr.h" #include "LootMgr.h"
#include "ItemEnchantmentMgr.h" #include "ItemEnchantmentMgr.h"
#include "MapManager.h" #include "MapManager.h"
@ -618,6 +619,8 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY, "MailDeliveryDelay", HOUR); setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY, "MailDeliveryDelay", HOUR);
setConfigMin(CONFIG_UINT32_MASS_MAILER_SEND_PER_TICK, "MassMailer.SendPerTick", 10, 1);
setConfigPos(CONFIG_UINT32_UPTIME_UPDATE, "UpdateUptimeInterval", 10); setConfigPos(CONFIG_UINT32_UPTIME_UPDATE, "UpdateUptimeInterval", 10);
if (reload) if (reload)
{ {
@ -1404,6 +1407,9 @@ void World::Update(uint32 diff)
///- Update the game time and check for shutdown time ///- Update the game time and check for shutdown time
_UpdateGameTime(); _UpdateGameTime();
///-Update mass mailer tasks if any
sMassMailMgr.Update();
/// Handle daily quests reset time /// Handle daily quests reset time
if (m_gameTime > m_NextDailyQuestReset) if (m_gameTime > m_NextDailyQuestReset)
ResetDailyQuests(); ResetDailyQuests();

View file

@ -131,6 +131,7 @@ enum eConfigUInt32Values
CONFIG_UINT32_START_GM_LEVEL, CONFIG_UINT32_START_GM_LEVEL,
CONFIG_UINT32_GROUP_VISIBILITY, CONFIG_UINT32_GROUP_VISIBILITY,
CONFIG_UINT32_MAIL_DELIVERY_DELAY, CONFIG_UINT32_MAIL_DELIVERY_DELAY,
CONFIG_UINT32_MASS_MAILER_SEND_PER_TICK,
CONFIG_UINT32_UPTIME_UPDATE, CONFIG_UINT32_UPTIME_UPDATE,
CONFIG_UINT32_AUCTION_DEPOSIT_MIN, CONFIG_UINT32_AUCTION_DEPOSIT_MIN,
CONFIG_UINT32_SKILL_CHANCE_ORANGE, CONFIG_UINT32_SKILL_CHANCE_ORANGE,

View file

@ -661,6 +661,11 @@ LogColors = ""
# Mail delivery delay time for item sending # Mail delivery delay time for item sending
# Default: 3600 sec (1 hour) # Default: 3600 sec (1 hour)
# #
# MassMailer.SendPerTick
# Max amount mail send each tick from mails list scheduled for mass mailer proccesing.
# More mails increase server load but speedup mass mail proccess. Normal tick length: 50 msecs, so 20 ticks in sec and 200 mails in sec by default.
# Default: 10
#
# SkillChance.Prospecting # SkillChance.Prospecting
# For prospecting skillup impossible by default, but can be allowed as custom setting # For prospecting skillup impossible by default, but can be allowed as custom setting
# Default: 0 - no skilups # Default: 0 - no skilups
@ -759,6 +764,7 @@ MaxPrimaryTradeSkill = 2
MinPetitionSigns = 9 MinPetitionSigns = 9
MaxGroupXPDistance = 74 MaxGroupXPDistance = 74
MailDeliveryDelay = 3600 MailDeliveryDelay = 3600
MassMailer.SendPerTick = 10
SkillChance.Prospecting = 0 SkillChance.Prospecting = 0
SkillChance.Milling = 0 SkillChance.Milling = 0
OffhandCheckAtTalentsReset = 0 OffhandCheckAtTalentsReset = 0

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "10969" #define REVISION_NR "10970"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__

View file

@ -436,6 +436,7 @@
<ClCompile Include="..\..\src\game\Mail.cpp" /> <ClCompile Include="..\..\src\game\Mail.cpp" />
<ClCompile Include="..\..\src\game\Map.cpp" /> <ClCompile Include="..\..\src\game\Map.cpp" />
<ClCompile Include="..\..\src\game\MapManager.cpp" /> <ClCompile Include="..\..\src\game\MapManager.cpp" />
<ClCompile Include="..\..\src\game\MassMailMgr.cpp" />
<ClCompile Include="..\..\src\game\MiscHandler.cpp" /> <ClCompile Include="..\..\src\game\MiscHandler.cpp" />
<ClCompile Include="..\..\src\game\MotionMaster.cpp" /> <ClCompile Include="..\..\src\game\MotionMaster.cpp" />
<ClCompile Include="..\..\src\game\MovementGenerator.cpp" /> <ClCompile Include="..\..\src\game\MovementGenerator.cpp" />
@ -592,6 +593,7 @@
<ClInclude Include="..\..\src\game\MapManager.h" /> <ClInclude Include="..\..\src\game\MapManager.h" />
<ClInclude Include="..\..\src\game\MapReference.h" /> <ClInclude Include="..\..\src\game\MapReference.h" />
<ClInclude Include="..\..\src\game\MapRefManager.h" /> <ClInclude Include="..\..\src\game\MapRefManager.h" />
<ClInclude Include="..\..\src\game\MassMailMgr.h" />
<ClInclude Include="..\..\src\game\MotionMaster.h" /> <ClInclude Include="..\..\src\game\MotionMaster.h" />
<ClInclude Include="..\..\src\game\MovementGenerator.h" /> <ClInclude Include="..\..\src\game\MovementGenerator.h" />
<ClInclude Include="..\..\src\game\NPCHandler.h" /> <ClInclude Include="..\..\src\game\NPCHandler.h" />

View file

@ -165,6 +165,9 @@
<ClCompile Include="..\..\src\game\MapManager.cpp"> <ClCompile Include="..\..\src\game\MapManager.cpp">
<Filter>World/Handlers</Filter> <Filter>World/Handlers</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\game\MassMailMgr.cpp">
<Filter>World/Handlers</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\MiscHandler.cpp"> <ClCompile Include="..\..\src\game\MiscHandler.cpp">
<Filter>World/Handlers</Filter> <Filter>World/Handlers</Filter>
</ClCompile> </ClCompile>
@ -579,6 +582,9 @@
<ClInclude Include="..\..\src\game\MapManager.h"> <ClInclude Include="..\..\src\game\MapManager.h">
<Filter>World/Handlers</Filter> <Filter>World/Handlers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\game\MassMailMgr.h">
<Filter>World/Handlers</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\NPCHandler.h"> <ClInclude Include="..\..\src\game\NPCHandler.h">
<Filter>World/Handlers</Filter> <Filter>World/Handlers</Filter>
</ClInclude> </ClInclude>

View file

@ -849,6 +849,14 @@
RelativePath="..\..\src\game\MapManager.h" RelativePath="..\..\src\game\MapManager.h"
> >
</File> </File>
<File
RelativePath="..\..\src\game\MassMailMgr.cpp"
>
</File>
<File
RelativePath="..\..\src\game\MassMailMgr.h"
>
</File>
<File <File
RelativePath="..\..\src\game\MiscHandler.cpp" RelativePath="..\..\src\game\MiscHandler.cpp"
> >

View file

@ -842,6 +842,14 @@
RelativePath="..\..\src\game\MapManager.h" RelativePath="..\..\src\game\MapManager.h"
> >
</File> </File>
<File
RelativePath="..\..\src\game\MassMailMgr.cpp"
>
</File>
<File
RelativePath="..\..\src\game\MassMailMgr.h"
>
</File>
<File <File
RelativePath="..\..\src\game\MiscHandler.cpp" RelativePath="..\..\src\game\MiscHandler.cpp"
> >