diff options
Diffstat (limited to 'public/gcsdk/gcsqlwritequeue.h')
| -rw-r--r-- | public/gcsdk/gcsqlwritequeue.h | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/public/gcsdk/gcsqlwritequeue.h b/public/gcsdk/gcsqlwritequeue.h new file mode 100644 index 0000000..a8141d4 --- /dev/null +++ b/public/gcsdk/gcsqlwritequeue.h @@ -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 + |