Files
mir_server/server/DBServer/DBDataServer.cpp
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

574 lines
16 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "StdAfx.h"
#include "FeeDb.h"
bool CDBDataServer::m_bGableIsClose =false;
CDBDataServer::CDBDataServer(CDBServer* lpDBEngine)
{
m_pDBServer = lpDBEngine;
SetServiceName("数据");
m_dwDeleteOutDataTick = 0;
m_SQLConnection.SetMultiThread(TRUE);
TICKCOUNT curTick = _getTickCount();
m_dwNextDumpTime = curTick + sDumpInterval;
m_dwSaveNameFile = curTick + sSaveNameInterval;
m_dwNextUpdateClientListTick = curTick + sUpdateLogicClientListInterval;
m_jobzyMgr.SetParam(&m_NowSQLConnection);
m_nNextZyJobSaveTime = curTick + 43200000; //12小时存一次盘
m_pCurClient = NULL;
m_CloseClientList.empty();
}
CDBDataServer::~CDBDataServer()
{
}
CCustomServerClientSocket* CDBDataServer::CreateClientSocket(SOCKET nSocket, PSOCKADDR_IN pAddrIn)
{
// 记录这个DBDataClient
m_pCurClient = new CDBDataClient(this, &m_NowSQLConnection, nSocket, pAddrIn);
m_pCurClient->SetNewSQLConnection(&m_SQLConnection);
return m_pCurClient;
}
VOID CDBDataServer::DestroyClientSocket(CCustomServerClientSocket *pClientSocket)
{
m_CloseClientLock.Lock();
CDBDataClient* pDC = (CDBDataClient*)pClientSocket;
for(INT_PTR i= m_CloseClientList.count() -1; i >=0; i-- )
{
if(m_CloseClientList[i] == pDC)
{
m_CloseClientLock.Unlock();
return;
}
}
OutputMsg(rmNormal, _T("Start to call datahandler.stop()"));
pDC->m_sDataHandler.Stop();
OutputMsg(rmNormal, _T("Call datahandler.stop() return"));
m_CloseClientList.add(pDC);
m_CloseClientLock.Unlock();
if ((void*)pClientSocket == (void*)m_pCurClient)
{
m_pCurClient = NULL;
}
}
VOID CDBDataServer::ProcessClients()
{
Inherited::ProcessClients();
ProcessClosedClients();
}
VOID CDBDataServer::DispatchInternalMessage(UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3,UINT64 uParam4)
{
TICKCOUNT nCurrentTick;
OutputMsg(rmTip, "CDBDataServer::DispatchInternalMessage:%d", uMsg);
switch(uMsg)
{
//向指定的服务器发送打开角色加载认证的消息(Param1=服务器ID,Param2=会话ID,Param3=角色ID)
case DSIM_POST_OPEN_CHAR_LOAD:
{
nCurrentTick = _getTickCount();
int nTime = (int)(nCurrentTick - uParam4);
OutputMsg(rmTip,"actorid=%lld,to DispatchInternalMessage, pass=%d ms",uParam3,nTime);
PostClientInternalMessages(uParam1, DCIM_SEND_LOAD_ACTOR, uParam2, uParam3, nCurrentTick,0);
}
break;
case DCIM_POST_CREATE_ACTOR_RESULT:
{
PostClientInternalMessages(uParam1, DCIM_CREATE_ACTOR_RESULT, uParam2, uParam3, uParam4,0);
break;
}
case DCIM_POST_CREATE_CS_ACTOR_RESULT:
{
PostClientInternalMessages(uParam1, DCIM_CREATE_CS_ACTOR_RESULT, uParam2, uParam3, uParam4,0);
break;
}
//向指定的服务器返回重命名角色的结果(Param1=服务器ID,Param2=操作结果,Param3=申请更名操作时传递的操作唯一标识)
case DSIM_POST_RENAMECHAR_RESULT:
//将此消息转发到指定ID内部数据客户端
PostClientInternalMessages(uParam1, DCIM_RENAMECHAR_RESULT, uParam2, uParam3, 0);
break;
//名称客户端向指定的服务器返回申请帮会ID的结果(Param1=服务器ID,
//Param2=2个INT_PTR的数组[0]保存操作结果,[1]保存帮会ID处理消息后必须对数组进行free释放,
//Param3=申请帮会ID操作时传递的操作唯一标识)
case DSIM_POST_ALLOC_GUILID_RESULT:
//将此消息转发到指定ID内部数据客户端
PostClientInternalMessages(uParam1, DCIM_ALLOC_GUILID_RESULT, ((PINT_PTR)uParam2)[0], ((PINT_PTR)uParam2)[1], uParam3);
//释放返回值数组
free((LPVOID)uParam2);
break;
}
}
VOID CDBDataServer::OnSocketDataThreadStop()
{
Inherited::OnSocketDataThreadStop();//调用父类的处理函数以便关闭所有连接
OutputMsg( rmTip, _T("正在等待所有数据客户端的数据处理完毕……"));
do
{
SingleRun();
Sleep(10);
}
while ( !AllDataProcessed() );
//强制释放所有客户端连接占用的内存(销毁连接对象)
FreeAllClient();
OutputMsg( rmTip, _T("所有数据客户端的数据已处理完毕!"));
}
VOID CDBDataServer::SingleRun()
{
//连接数据库
ConnectSQL();
Inherited::SingleRun();
}
VOID CDBDataServer::OnRun()
{
TICKCOUNT dwCurTick = _getTickCount();
////每分钟从数据库中删除一次过期数据,过期数据在保存角色数据的时候将角色对应的
////物品、技能、任务等数据的charid字段更新为了0将多次零散的SQL delete操作合并
////为多次update一次delete以提高数据库操作性能
if ( m_NowSQLConnection.Connected() && dwCurTick >= m_dwDeleteOutDataTick )
{
if(m_dwDeleteOutDataTick)
{
// //删除过期背包物品
if ( !m_NowSQLConnection.Exec( "delete from actorbagitem where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期装备物品
if ( !m_NowSQLConnection.Exec( "delete from actorequipitem where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期仓库物品
if ( !m_NowSQLConnection.Exec( "delete from actordepotitem where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期技能
if ( !m_NowSQLConnection.Exec( "delete from skill where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期任务进度
if ( !m_NowSQLConnection.Exec( "delete from goingquest where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期完成任务数据
if ( !m_NowSQLConnection.Exec( "delete from repeatquest where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期的好友数据
if ( !m_NowSQLConnection.Exec( "delete from actorfriends where actorid = 0;" ) )
m_NowSQLConnection.ResetQuery();
//删除过期的宠物数据
if (!m_NowSQLConnection.Exec("delete from actorpets where actorid=0;"))
m_NowSQLConnection.ResetQuery();
if (!m_NowSQLConnection.Exec("delete from actorpetitem where actorid=0;"))
m_NowSQLConnection.ResetQuery();
if (!m_NowSQLConnection.Exec("delete from petskills where actorid=0;"))
m_NowSQLConnection.ResetQuery();
if (!m_NowSQLConnection.Exec("delete from actorrelation where actorid=0;"))
m_NowSQLConnection.ResetQuery();
}
m_dwDeleteOutDataTick = dwCurTick + 60000;
}
if(m_SQLConnection.Connected() && dwCurTick >= m_dwNextDumpTime)
{
//每5分钟dump一次
if(m_dwNextDumpTime)
{
CTimeProfMgr::getSingleton().dump();
}
m_dwNextDumpTime = dwCurTick + sDumpInterval; //5分钟执行一次dump
}
if ( dwCurTick >= m_dwSaveNameFile)//保存随机名字的文件
{
if(m_dwSaveNameFile)
{
//m_pDBServer->SaveNameFile();
}
m_dwSaveNameFile += sSaveNameInterval;//5分钟保存一次
}
if (dwCurTick >= m_dwNextUpdateClientListTick)
{
UpdateLogicClientList();
m_dwNextUpdateClientListTick = dwCurTick + sUpdateLogicClientListInterval;
}
if (m_nNextZyJobSaveTime <= dwCurTick)
{
//现在只有职业数据需要存盘
if (m_jobzyMgr.HasLoadJobData() && m_NowSQLConnection.Connected())
{
m_jobzyMgr.SaveJobData();
}
m_nNextZyJobSaveTime = dwCurTick + 43200000; //12个小时存一次
}
// 读取充值指令
if (m_FeeSQLConnection.Connected() && dwCurTick >= m_nNextReadFeeTime)
{
char token[128];
if (m_pCurClient && m_pCurClient->connected())
{
int nError = m_FeeSQLConnection.Query("call loadfee_notice(%d);", CDBServer::s_pDBEngine->getServerIndex());
if ( !nError )
{
if (MYSQL_ROW pRow = m_FeeSQLConnection.CurrentRow())
{
int nCount = m_FeeSQLConnection.GetRowCount();
CDataPacket& out = m_pCurClient->allocProtoPacket(dcNoticeFee);
INT_PTR pos = out.getPosition();
out << (int)0;
nCount = 0;
unsigned int nActorId;
ACCOUNT sAccount;
do
{
sscanf(pRow[0], "%u", &nActorId);
strlcpy((sAccount), (pRow[1]? pRow[1] : ""), sizeof(sAccount));
if(nActorId != 0) {
if (m_ActorIdMap[nActorId])
{
nCount++;
OutputMsg(rmTip,_T("[Fee]0-1 充值通知在线ActorId%dAccount%s"),nActorId,sAccount);
out << nActorId;
out.writeString(sAccount);
} else {
OutputMsg(rmTip,_T("[Fee]0-2 充值通知离线ActorId%dAccount%s"),nActorId,sAccount);
}
} else {
nCount++;
OutputMsg(rmTip,_T("[Fee]0-3 充值通知不指定角色ActorId%dAccount%s"),nActorId,sAccount);
out << nActorId;
out.writeString(sAccount);
}
}
while(pRow = m_FeeSQLConnection.NextRow());
int* pCount = (int*)out.getPositionPtr(pos);
*pCount = nCount;
m_pCurClient->flushProtoPacket(out);
}
m_FeeSQLConnection.ResetQuery();
}
else
{
OutputMsg(rmTip, _T("m_FeeSQLConnection serverindex:%d nError:%d"),CDBServer::s_pDBEngine->getServerIndex(), nError);
}
m_nNextReadFeeTime = dwCurTick + 1000;
}
}
}
void CDBDataServer::UpdateLogicClientList()
{
char szData[10240];
CDataPacket packet(szData, sizeof(szData));
packet.setLength(0);
size_t nPos = packet.getPosition();
CBaseList<int> sList;
CDBDataClient *pClient;
for (INT_PTR i = 0; i < m_ClientList.count(); i++)
{
pClient = (CDBDataClient *)m_ClientList[i];
if (pClient->registed())
{
sList.add((int)pClient->getClientServerIndex());
}
}
//OutputMsg(rmError, _T("%s update client list, count=%d"), __FUNCTION__, (int)sList.count());
/*
CDBCenterClient *pDBCenterClient = GetDBEngine()->getDBCenterClient();
pDBCenterClient->PostUpdateLogicClientList(sList);
*/
}
void CDBDataServer::Trace()
{
OutputMsg(rmNormal,"CDBDataServer Trace start...");
CDBDataClient *pClient;
for (INT_PTR i = 0; i < m_ClientList.count(); i++)
{
pClient = (CDBDataClient *)m_ClientList[i];
if (pClient && pClient->registed() )
{
pClient->Trace();
}
}
OutputMsg(rmNormal,"CDBDataServer Trace end...");
}
INT_PTR CDBDataServer::SendDataClientMsg(const INT_PTR nServerIndex, LPCVOID lpData, SIZE_T dwSize)
{
INT_PTR i, nResult = 0;
CDBDataClient *pClient;
for (i=m_ClientList.count()-1; i>-1; --i)
{
pClient = (CDBDataClient*)m_ClientList[i];
if ( pClient->registed() )
{
if ( !nServerIndex || pClient->getClientServerIndex() == nServerIndex )
{
pClient->AppendSendBuffer(lpData, dwSize);
nResult++;
}
}
}
return nResult;
}
BOOL CDBDataServer::getGameReady(int nSrvIdx)
{
INT_PTR i;
BOOL result = FALSE;
CDBDataClient *pClient;
for (i=m_ClientList.count()-1; i>-1; --i)
{
pClient = (CDBDataClient*)m_ClientList[i];
if ( pClient->registed() )
{
if ( !nSrvIdx || pClient->getClientServerIndex() == nSrvIdx )
{
result = TRUE;
break;
}
}
}
return result;
}
INT_PTR CDBDataServer::PostClientInternalMessages(UINT64 nServerIndex, UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3,UINT64 uParam4)
{
INT_PTR i, nResult = 0;
CDBDataClient *pClient;
for (i=m_ClientList.count()-1; i>-1; --i)
{
pClient = (CDBDataClient*)m_ClientList[i];
if ( pClient->registed() )
{
if ( !nServerIndex || pClient->getClientServerIndex() == nServerIndex )
{
pClient->PostInternalMessage(uMsg, uParam1, uParam2, uParam3,uParam4);
nResult++;
}
}
}
return nResult;
}
BOOL CDBDataServer::ConnectSQL()
{
if ( !m_SQLConnection.Connected() )
{
if ( _getTickCount() >= m_dwReconnectSQLTick )
{
m_pDBServer->SetupSQLConnection(&m_SQLConnection);
if ( m_SQLConnection.Connect() )
{
if (m_pDBServer->IsUtf8())
{
if (mysql_set_character_set(m_SQLConnection.GetMySql(),"utf8"))
{
OutputMsg( rmError, _T("设置utf8编码出错 !!!") );
}
}
//mysql_options(m_SQLConnection.GetMySql(), MYSQL_SET_CHARSET_NAME, "utf8");
//if (m_SQLConnection.Exec("charset utf8"))
//{
// OutputMsg( rmError, _T("设置utf8字符编码出错"));
//}
//else
//{
// m_SQLConnection.ResetQuery();
//}
return TRUE;
}
//如果连接SQL失败则将在5秒后重试
m_dwReconnectSQLTick = _getTickCount() + 5 * 1000;
return FALSE;
}
}
if (!m_FeeSQLConnection.Connected())
{
if ( _getTickCount() >= m_dwReconnectSQLTick )
{
m_pDBServer->SetupSQLConnection(&m_FeeSQLConnection);
OutputMsg(rmTip, _T("m_FeeSQLConnection fail "));
if ( m_FeeSQLConnection.Connect() )
{
OutputMsg(rmTip, _T("m_FeeSQLConnection success"));
return TRUE;
}
//如果连接SQL失败则将在5秒后重试
m_dwReconnectSQLTick = _getTickCount() + 5 * 1000;
return FALSE;
}
}
if (!m_NowSQLConnection.Connected())
{
if ( _getTickCount() >= m_dwReconnectSQLTick )
{
m_pDBServer->SetupSQLConnection(&m_NowSQLConnection);
OutputMsg(rmTip, _T("m_NowSQLConnection fail "));
if ( m_NowSQLConnection.Connect() )
{
if (m_pDBServer->IsUtf8())
{
if (mysql_set_character_set(m_NowSQLConnection.GetMySql(),"utf8"))
{
OutputMsg( rmError, _T("设置utf8编码出错 !!!") );
}
}
m_jobzyMgr.LoadJobInitData();
//m_jobzyMgr.LoadZyInitData(); //阵营的数据暂时屏蔽
m_jobzyMgr.LoadActorNameInitData();
m_jobzyMgr.LoadGuildNameInitData();//行会名字
OutputMsg(rmTip, _T("NowSQL mysql connection character set: %s"), mysql_character_set_name(m_NowSQLConnection.GetMySql()));
// OutputMsg(rmTip, _T("m_NowSQLConnection success()"));
return TRUE;
}
//如果连接SQL失败则将在5秒后重试
m_dwReconnectSQLTick = _getTickCount() + 5 * 1000;
return FALSE;
}
}
return TRUE;
}
VOID CDBDataServer::ProcessClosedClients()
{
INT_PTR i;
CDBDataClient *pClient;
TICKCOUNT dwCurTick = _getTickCount();
//必须降序循环,因为连接可能在循环中被移除
for ( i=m_CloseClientList.count()-1; i>-1; --i )
{
pClient = m_CloseClientList[i];
//连接被关闭后依然要调用Run函数因为可能有重要的网络数据或逻辑数据没有处理完
pClient->Run();
//连接关闭5分钟后再释放连接对象
if ((dwCurTick - pClient->m_dwClosedTick >= 5 * 60 * 1000) || pClient->m_dwClosedTick == 0)
{
m_CloseClientList.remove(i);
delete pClient;
}
}
}
BOOL CDBDataServer::AllDataProcessed()
{
INT_PTR i;
CDBDataClient *pClient;
//如果消息队列非空则仍需继续处理
if ( getInternalMessageCount() > 0 )
return FALSE;
//判断数据客户端的数据是否处理完毕
for ( i=m_ClientList.count()-1; i>-1; --i )
{
pClient = (CDBDataClient*)m_ClientList[i];
if ( !pClient->registed() )
continue;
if ( pClient->HasRemainData() )
return FALSE;
}
for ( i=m_CloseClientList.count()-1; i>-1; --i )
{
pClient = m_CloseClientList[i];
if ( !pClient->registed() )
continue;
if ( pClient->HasRemainData() )
return FALSE;
}
return TRUE;
}
VOID CDBDataServer::FreeAllClient()
{
INT_PTR i;
CDBDataClient *pClient;
//关闭所有客户端
CloseAllClients();
//销毁所有连接
for ( i=m_CloseClientList.count()-1; i>-1; --i )
{
pClient = m_CloseClientList[i];
//delete pClient;
pClient->m_dwClosedTick = 0;
}
//m_CloseClientList.clear();
}
INT_PTR CDBDataServer::GetAvailableDataClientCount(const INT_PTR nServerIndex)
{
//OutputMsg( rmTip, _T("GetAvailableDataClientCount():nServerIndex=%d"),nServerIndex );
if ( nServerIndex == 0 )
{
return m_ClientList.count();
}
INT_PTR i, nResult = 0;
CDBDataClient *pClient;
m_ClientList.lock();
for ( i=m_ClientList.count() - 1; i > - 1; --i )
{
pClient = (CDBDataClient*)m_ClientList[i];
if ( pClient->connected() && pClient->getClientServerIndex() == nServerIndex )
{
nResult++;
}
else
{
//test
//OutputMsg( rmError, _T("connected()=%d,ClientIndex=%d"),(int)(pClient->connected()),pClient->getClientServerIndex() );
}
}
m_ClientList.unlock();
return nResult;
}
BOOL CDBDataServer::IsCharSavedFailure(const INT_PTR nCharId)
{
//测试先返回FALSE
return FALSE;
}