|
|
//========= Copyright � 1996-2005, 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(); }
|