You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
5.6 KiB
193 lines
5.6 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
|
||
|
#include "MySqlDatabase.h"
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Constructor
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CMySqlDatabase::CMySqlDatabase()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Destructor
|
||
|
// blocks until db process thread has stopped
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CMySqlDatabase::~CMySqlDatabase()
|
||
|
{
|
||
|
// flag the thread to stop
|
||
|
m_bRunThread = false;
|
||
|
|
||
|
// pulse the thread to make it run
|
||
|
::SetEvent(m_hEvent);
|
||
|
|
||
|
// make sure it's done
|
||
|
::EnterCriticalSection(&m_csThread);
|
||
|
::LeaveCriticalSection(&m_csThread);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Thread access function
|
||
|
//-----------------------------------------------------------------------------
|
||
|
static DWORD WINAPI staticThreadFunc(void *param)
|
||
|
{
|
||
|
((CMySqlDatabase *)param)->RunThread();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Establishes connection to the database and sets up this object to handle db command
|
||
|
// Output : Returns true on success, false on failure.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CMySqlDatabase::Initialize()
|
||
|
{
|
||
|
// prepare critical sections
|
||
|
//!! need to download SDK and replace these with InitializeCriticalSectionAndSpinCount() calls
|
||
|
::InitializeCriticalSection(&m_csThread);
|
||
|
::InitializeCriticalSection(&m_csInQueue);
|
||
|
::InitializeCriticalSection(&m_csOutQueue);
|
||
|
::InitializeCriticalSection(&m_csDBAccess);
|
||
|
|
||
|
// initialize wait calls
|
||
|
m_hEvent = ::CreateEvent(NULL, false, true, NULL);
|
||
|
|
||
|
// start the DB-access thread
|
||
|
m_bRunThread = true;
|
||
|
|
||
|
unsigned long threadID;
|
||
|
::CreateThread(NULL, 0, staticThreadFunc, this, 0, &threadID);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Main thread loop
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CMySqlDatabase::RunThread()
|
||
|
{
|
||
|
::EnterCriticalSection(&m_csThread);
|
||
|
while (m_bRunThread)
|
||
|
{
|
||
|
if (m_InQueue.Count() > 0)
|
||
|
{
|
||
|
// get a dispatched DB request
|
||
|
::EnterCriticalSection(&m_csInQueue);
|
||
|
|
||
|
// pop the front of the queue
|
||
|
int headIndex = m_InQueue.Head();
|
||
|
msg_t msg = m_InQueue[headIndex];
|
||
|
m_InQueue.Remove(headIndex);
|
||
|
|
||
|
::LeaveCriticalSection(&m_csInQueue);
|
||
|
|
||
|
::EnterCriticalSection(&m_csDBAccess);
|
||
|
|
||
|
// run sqldb command
|
||
|
msg.result = msg.cmd->RunCommand();
|
||
|
|
||
|
::LeaveCriticalSection(&m_csDBAccess);
|
||
|
|
||
|
if (msg.replyTarget)
|
||
|
{
|
||
|
// put the results in the outgoing queue
|
||
|
::EnterCriticalSection(&m_csOutQueue);
|
||
|
m_OutQueue.AddToTail(msg);
|
||
|
::LeaveCriticalSection(&m_csOutQueue);
|
||
|
|
||
|
// wake up out queue
|
||
|
msg.replyTarget->WakeUp();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// there is no return data from the call, so kill the object now
|
||
|
msg.cmd->deleteThis();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// nothing in incoming queue, so wait until we get the signal
|
||
|
::WaitForSingleObject(m_hEvent, INFINITE);
|
||
|
}
|
||
|
|
||
|
// check the size of the outqueue; if it's getting too big, sleep to let the main thread catch up
|
||
|
if (m_OutQueue.Count() > 50)
|
||
|
{
|
||
|
::Sleep(2);
|
||
|
}
|
||
|
}
|
||
|
::LeaveCriticalSection(&m_csThread);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Adds a database command to the queue, and wakes the db thread
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CMySqlDatabase::AddCommandToQueue(ISQLDBCommand *cmd, ISQLDBReplyTarget *replyTarget, int returnState)
|
||
|
{
|
||
|
::EnterCriticalSection(&m_csInQueue);
|
||
|
|
||
|
// add to the queue
|
||
|
msg_t msg = { cmd, replyTarget, 0, returnState };
|
||
|
m_InQueue.AddToTail(msg);
|
||
|
|
||
|
::LeaveCriticalSection(&m_csInQueue);
|
||
|
|
||
|
// signal the thread to start running
|
||
|
::SetEvent(m_hEvent);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Dispatches responses to SQLDB queries
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CMySqlDatabase::RunFrame()
|
||
|
{
|
||
|
bool doneWork = false;
|
||
|
|
||
|
while (m_OutQueue.Count() > 0)
|
||
|
{
|
||
|
::EnterCriticalSection(&m_csOutQueue);
|
||
|
|
||
|
// pop the first item in the queue
|
||
|
int headIndex = m_OutQueue.Head();
|
||
|
msg_t msg = m_OutQueue[headIndex];
|
||
|
m_OutQueue.Remove(headIndex);
|
||
|
|
||
|
::LeaveCriticalSection(&m_csOutQueue);
|
||
|
|
||
|
// run result
|
||
|
if (msg.replyTarget)
|
||
|
{
|
||
|
msg.replyTarget->SQLDBResponse(msg.cmd->GetID(), msg.returnState, msg.result, msg.cmd->GetReturnData());
|
||
|
|
||
|
// kill command
|
||
|
// it would be a good optimization to be able to reuse these
|
||
|
msg.cmd->deleteThis();
|
||
|
}
|
||
|
|
||
|
doneWork = true;
|
||
|
}
|
||
|
|
||
|
return doneWork;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: load info - returns the number of sql db queries waiting to be processed
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int CMySqlDatabase::QueriesInOutQueue()
|
||
|
{
|
||
|
// the queue names are from the DB point of view, not the server - thus the reversal
|
||
|
return m_InQueue.Count();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: number of queries finished processing, waiting to be responded to
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int CMySqlDatabase::QueriesInFinishedQueue()
|
||
|
{
|
||
|
return m_OutQueue.Count();
|
||
|
}
|