Files
Leviathan/Server/GameServer/Game/Db/GameDBManager.h
T
2026-06-01 12:46:52 +02:00

205 lines
4.6 KiB
C++

#pragma once
#include <toolkit/XBossWorker.h>
#include <dump/XExceptionHandler.h>
#include <toolkit/ILock.h>
#include <cassert>
#include <list>
#include "ADOConnection.h"
void db_thread_init_func( int nThreadNum );
extern class GameDBManager & DB();
class GameDBManager
{
public:
struct DBProc : public XBossWorker::XWorker
{
DBProc( const char *_szProcName = NULL, bool _bNeedToContinueOnFail = false )
: szProcName( _szProcName )
, szStoredProcedureName( NULL )
, bNeedToContinueOnFail( _bNeedToContinueOnFail )
{
LARGE_INTEGER li;
QueryPerformanceCounter( &li );
creationTime = li;
memset( szStoredProcedureDebugInfo, 0, sizeof( szStoredProcedureDebugInfo ) );
}
virtual ~DBProc() {}
virtual bool onProcess( DBConnection & db ) = 0;
virtual void onEnd( bool bIsCancel ) {}
virtual bool onProcess( int nThreadNum );
virtual const std::string getDebugInfo() { return "No debug info"; }
virtual void onFail( const _com_error & exception ) {}
virtual void setDBQueryQueue( class DBQueryQueue *p ) { pQueryQueue = p; }
virtual bool operator==( const DBProc & rh ) { return false; }
void * operator new( size_t nAllocSize );
void * operator new[]( size_t nArraySize );
void operator delete( void * pBlock );
void operator delete[]( void * pBlock );
class DBQueryQueue *pQueryQueue;
const char *szProcName;
const char *szStoredProcedureName;
char szStoredProcedureDebugInfo[256];
bool bNeedToContinueOnFail;
LARGE_INTEGER creationTime;
static void IncExeQueryCount() { InterlockedIncrement( &m_lExecQueryCount ); }
static int GetExecQueryCountPerSec()
{
DWORD dwNowTick = ::GetTickCount();
DWORD dwAccumulateTick = dwNowTick - m_dwStartTick;
if( dwAccumulateTick < 1000 )
{
return m_lExecQueryCount;
}
int nQueryCount = static_cast< int >( m_lExecQueryCount / (dwAccumulateTick/1000.) );
m_lExecQueryCount = 0;
m_dwStartTick = dwNowTick;
return nQueryCount;
}
static volatile DWORD m_dwStartTick;
static volatile long m_lExecQueryCount;
};
GameDBManager();
virtual ~GameDBManager()
{
if( m_pGameConnection ) DeInitGameDB();
if( m_ThreadPool.GetThreadCount() ) EndThread();
}
void InitDBStatusObserver();
bool InitGameDB( unsigned thread_number,
const char *szConnectionString,
const char *szAccount,
const char *szPassword );
bool DeInitGameDB();
bool StartThread( int thread_number )
{
return m_ThreadPool.StartThread( "DB", thread_number, THREAD_PRIORITY_NORMAL, db_thread_init_func, true );
}
bool EndThread()
{
return m_ThreadPool.EndThread();
}
bool Push( DBProc * pWork );
DBConnection & GetGameDBConnection( int nThreadIndex )
{
return m_pGameConnection[ nThreadIndex ];
}
size_t GetWaitingWorkCount() { return m_ThreadPool.GetWaitingWorkCount(); }
long GetThreadCount() { return m_ThreadPool.GetThreadCount(); }
long GetActiveThreadCount() { return m_ThreadPool.GetActiveThreadCount(); }
long GetPendingWorkCount() { return m_ThreadPool.GetPendingWorkCount(); }
long GetTotalWorkCount() { return m_ThreadPool.GetTotalWorkCount(); }
private:
bool initDBConnection( DBConnection* & pConnection,
unsigned thread_number,
const char *szConnectionString,
const char *szAccount,
const char *szPassword );
friend struct GameDBStatObserber;
DBConnection* m_pGameConnection;
XBossWorker m_ThreadPool;
};
class DBQueryQueue
{
public:
DBQueryQueue( GameDBManager* pManager ) : m_pManager( pManager )
{
m_nDelay = 0;
};
XCriticalSection & GetLock() { return m_Lock; }
bool DBQuery( GameDBManager::DBProc * pWork, bool bDeleteIfCached = true )
{
THREAD_SYNCRONIZE( m_Lock );
// 동일 쿼리가 대기중이면 무시..
for( std::list< GameDBManager::DBProc* >::iterator it = m_listQuery.begin(); it != m_listQuery.end(); ++it )
{
if( (*pWork) == *(*it) )
{
if( bDeleteIfCached ) delete pWork;
return false;
}
}
pWork->setDBQueryQueue( this );
bool bIsEmpty = m_listQuery.empty();
m_listQuery.push_back( pWork );
if( bIsEmpty )
{
return m_pManager->Push( pWork );
}
return true;
}
void onEndQuery()
{
THREAD_SYNCRONIZE( m_Lock );
m_listQuery.pop_front();
if( !m_listQuery.empty() )
{
DB().Push( m_listQuery.front() );
}
}
int GetQueryCount()
{
THREAD_SYNCRONIZE( m_Lock );
return (int)m_listQuery.size();
}
void SetLockName( const char* name )
{
m_Lock.m_strName = name;
}
private:
std::list< GameDBManager::DBProc* > m_listQuery;
GameDBManager* m_pManager;
int m_nDelay;
XCriticalSection m_Lock;
};