mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-11 19:29:08 +00:00
1
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
//====== Copyright ©, Valve Corporation, All rights reserved. =======
|
||||
// GCSqlWriteQueue.h
|
||||
//
|
||||
// A utility class that allows for templating based upon a SQL schema type, and then
|
||||
// queuing up a number of those records to be written to SQL. This will buffer them until
|
||||
// either a certain number have been queued or a period of time has elapsed, at which point
|
||||
// it will flush them to SQL in a single transaction.
|
||||
//
|
||||
//===================================================================
|
||||
#ifndef GCSQLWRITEQUEUE_H
|
||||
#define GCSQLWRITEQUEUE_H
|
||||
|
||||
#include "scheduledfunction.h"
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
|
||||
class CGCBase;
|
||||
|
||||
template < typename TSqlClass >
|
||||
class CGCSQLWriteQueue
|
||||
{
|
||||
public:
|
||||
|
||||
CGCSQLWriteQueue( uint32 nMaxToCache, uint32 nMaxMSToWrite ) :
|
||||
m_nMaxToCache( nMaxToCache ),
|
||||
m_nMaxMSToWrite( nMaxMSToWrite )
|
||||
{
|
||||
m_QueuedRecords.EnsureCapacity( nMaxToCache );
|
||||
}
|
||||
|
||||
//called to queue the record for writing, which will occur either when the maximum time between writebacks has occurred, or
|
||||
//when the cache has filled up
|
||||
void QueueRecord( const TSqlClass& sch )
|
||||
{
|
||||
m_QueuedRecords.AddToTail( sch );
|
||||
|
||||
//now handle either dispatching, or scheduling a timeout dispatch
|
||||
if( ( uint32 )m_QueuedRecords.Count() >= m_nMaxToCache )
|
||||
{
|
||||
//unschedule first. This way if while we are yielded, we add another entry, it can schedule a new timeout
|
||||
m_TimeCommit.Cancel();
|
||||
CreateJobToCommitSQL();
|
||||
}
|
||||
else if( !m_TimeCommit.BIsScheduled() )
|
||||
{
|
||||
m_TimeCommit.Schedule( this, &CGCSQLWriteQueue< TSqlClass >::CreateJobToCommitSQL, m_nMaxMSToWrite );
|
||||
}
|
||||
}
|
||||
|
||||
//a yielding version of the above function
|
||||
void YieldingQueueRecord( const TSqlClass& sch )
|
||||
{
|
||||
m_QueuedRecords.AddToTail( sch );
|
||||
|
||||
//now handle either dispatching, or scheduling a timeout dispatch
|
||||
if( ( uint32 )m_QueuedRecords.Count() >= m_nMaxToCache )
|
||||
{
|
||||
//unschedule first. This way if while we are yielded, we add another entry, it can schedule a new timeout
|
||||
m_TimeCommit.Cancel();
|
||||
YieldingFlushQueuedViewsToSQL();
|
||||
}
|
||||
else if( !m_TimeCommit.BIsScheduled() )
|
||||
{
|
||||
m_TimeCommit.Schedule( this, &CGCSQLWriteQueue< TSqlClass >::CreateJobToCommitSQL, m_nMaxMSToWrite );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//called internally when we kick off a job after N amount of time has expired
|
||||
template < typename TSqlClass >
|
||||
class CTimeExpiredCommitJob : public CGCJob
|
||||
{
|
||||
public:
|
||||
CTimeExpiredCommitJob( CGCBase* pGC, CGCSQLWriteQueue< TSqlClass >* pClass ) : CGCJob( pGC ), m_pClass( pClass ) {}
|
||||
virtual bool BYieldingRunJob( void* pvStartParm )
|
||||
{
|
||||
m_pClass->YieldingFlushQueuedViewsToSQL();
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
CGCSQLWriteQueue< TSqlClass >* m_pClass;
|
||||
};
|
||||
|
||||
//the function called when time expires to start a job and commit the requests to SQL
|
||||
void CreateJobToCommitSQL()
|
||||
{
|
||||
//kick off our job, which just calls the flush
|
||||
CGCJob* pJob = new CTimeExpiredCommitJob< TSqlClass >( GGCBase(), this );
|
||||
pJob->StartJobDelayed( NULL );
|
||||
}
|
||||
|
||||
//handles committing the list of queued views to SQL
|
||||
void YieldingFlushQueuedViewsToSQL()
|
||||
{
|
||||
if( m_QueuedRecords.Count() == 0 )
|
||||
return;
|
||||
|
||||
//move the contents into a local vector so we don't have any conflicts of global state
|
||||
CUtlVector< TSqlClass > localQueue;
|
||||
localQueue.Swap( m_QueuedRecords );
|
||||
//prepare the queue for the next batch (so we don't have intermediate resizes)
|
||||
m_QueuedRecords.EnsureCapacity( m_nMaxToCache );
|
||||
|
||||
// start a transaction for all this work
|
||||
CSQLAccess sqlAccess;
|
||||
sqlAccess.BBeginTransaction( "CGCWatchDownloadedReplayJob::FlushQueuedViewsToSQL" );
|
||||
|
||||
FOR_EACH_VEC( localQueue, nCurrView )
|
||||
{
|
||||
sqlAccess.BYieldingInsertRecord( &localQueue[ nCurrView ] );
|
||||
}
|
||||
|
||||
sqlAccess.BCommitTransaction();
|
||||
}
|
||||
|
||||
//the records that we have queued
|
||||
CUtlVector< TSqlClass > m_QueuedRecords;
|
||||
//schedules a write back to ensure we commit at least every N seconds
|
||||
CScheduledFunction< CGCSQLWriteQueue< TSqlClass > > m_TimeCommit;
|
||||
//maximum number of seconds between commits
|
||||
uint32 m_nMaxMSToWrite;
|
||||
//maximum number of records to buffer before writing back
|
||||
uint32 m_nMaxToCache;
|
||||
};
|
||||
|
||||
} //namespace GCSDK
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user