summaryrefslogtreecommitdiff
path: root/replay/sv_fileservercleanup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'replay/sv_fileservercleanup.cpp')
-rw-r--r--replay/sv_fileservercleanup.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/replay/sv_fileservercleanup.cpp b/replay/sv_fileservercleanup.cpp
new file mode 100644
index 0000000..c3ac061
--- /dev/null
+++ b/replay/sv_fileservercleanup.cpp
@@ -0,0 +1,260 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//=======================================================================================//
+
+#include "sv_fileservercleanup.h"
+#include "sv_replaycontext.h"
+#include "sv_recordingsession.h"
+#include "spew.h"
+
+#if BUILD_CURL
+#include "curl/curl.h"
+#endif
+
+#undef AddJob
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//----------------------------------------------------------------------------------------
+
+#if _DEBUG
+ConVar replay_fileserver_simulate_delete( "replay_fileserver_simulate_delete", "0", FCVAR_GAMEDLL, "Don't delete any actual files during replay cleanup." );
+#endif
+
+//----------------------------------------------------------------------------------------
+
+IFileserverCleanerJob *SV_CastJobToIFileserverCleanerJob( CBaseJob *pJob )
+{
+ IFileserverCleanerJob *pResult = dynamic_cast< IFileserverCleanerJob * >( pJob );
+ AssertMsg( pResult != NULL, "Cast failed! Are you sure this job is an IFileserverCleanerJob?" );
+ return pResult;
+}
+
+//----------------------------------------------------------------------------------------
+
+CFileserverCleaner::CFileserverCleaner()
+: m_bRunning( false ),
+ m_bPrintResult( false ),
+ m_pCleanerJob( NULL ),
+ m_pSpewer( NULL ),
+ m_nNumFilesDeleted( 0 )
+{
+}
+
+void CFileserverCleaner::MarkFileForDelete( const char *pFilename )
+{
+ if ( m_bRunning )
+ return;
+
+ // Create cleaner job now if need be
+ if ( !m_pCleanerJob )
+ {
+ m_pCleanerJob = SV_CreateDeleteFileJob();
+ m_nNumFilesDeleted = 0;
+ }
+
+ IFileserverCleanerJob *pCleanerJobImp = SV_CastJobToIFileserverCleanerJob( m_pCleanerJob );
+ AssertMsg( pCleanerJobImp != NULL, "This cast should always work!" );
+ if ( pCleanerJobImp )
+ {
+ pCleanerJobImp->AddFileForDelete( pFilename );
+ }
+}
+
+void CFileserverCleaner::BlockForCompletion()
+{
+ if ( !m_bRunning )
+ return;
+
+ if ( !m_pCleanerJob )
+ return;
+
+ m_pCleanerJob->WaitForFinish();
+
+ Clear();
+}
+
+void CFileserverCleaner::DoCleanAsynchronous( bool bPrintResult/*=false*/, ISpewer *pSpewer/*=g_pDefaultSpewer*/ )
+{
+ if ( m_bRunning )
+ return;
+
+ if ( !m_pCleanerJob )
+ return;
+
+ m_pSpewer = pSpewer;
+ m_bPrintResult = bPrintResult;
+ m_bRunning = true;
+
+ SV_GetThreadPool()->AddJob( m_pCleanerJob );
+}
+
+void CFileserverCleaner::Clear()
+{
+ m_pCleanerJob->Release();
+ m_pCleanerJob = NULL;
+
+ m_bPrintResult = false;
+ m_bRunning = false;
+}
+
+void CFileserverCleaner::Think()
+{
+ CBaseThinker::Think();
+
+ if ( !m_bRunning )
+ return;
+
+ if ( !m_pCleanerJob->IsFinished() )
+ return;
+
+ IFileserverCleanerJob *pCleanerJobImp = SV_CastJobToIFileserverCleanerJob( m_pCleanerJob );
+ if ( pCleanerJobImp )
+ {
+ m_nNumFilesDeleted += pCleanerJobImp->GetNumFilesDeleted();
+ }
+
+ PrintResult();
+ Clear();
+}
+
+void CFileserverCleaner::PrintResult()
+{
+ if ( !m_bPrintResult || !m_pSpewer )
+ return;
+
+ m_pSpewer->PrintEmptyLine();
+
+ const int nNumFilesRemoved = SV_GetFileserverCleaner()->GetNumFilesDeleted();
+ m_pSpewer->PrintValue( "Number of files removed", Replay_va( "%i", nNumFilesRemoved ) );
+
+ m_pSpewer->PrintBlockEnd();
+}
+
+
+float CFileserverCleaner::GetNextThinkTime() const
+{
+ return 0.0f;
+}
+
+//----------------------------------------------------------------------------------------
+
+CLocalFileDeleterJob::CLocalFileDeleterJob()
+: m_nNumDeleted( 0 )
+{
+}
+
+void CLocalFileDeleterJob::AddFileForDelete( const char *pFilename )
+{
+ CFmtStr fmtFullFilename( "%s%s", g_pServerReplayContext->GetLocalFileServerPath(), pFilename );
+ m_vecFiles.CopyAndAddToTail( fmtFullFilename.Access() );
+}
+
+JobStatus_t CLocalFileDeleterJob::DoExecute()
+{
+ bool bResult = true;
+
+ FOR_EACH_VEC( m_vecFiles, i )
+ {
+ const char *pCurFilename = m_vecFiles[ i ];
+
+ // File exists?
+ PrintEventStartMsg( "File exists?" );
+ if ( !g_pFullFileSystem->FileExists( pCurFilename ) )
+ {
+ CFmtStr fmtError( "File '%s' does not exist", pCurFilename );
+ SetError( ERROR_FILE_DOES_NOT_EXIST, fmtError.Access() ); // TODO: This will only catch the last filename
+ PrintEventResult( false );
+ bResult = false;
+ continue;
+ }
+ PrintEventResult( true );
+
+ // Delete the file
+ PrintEventStartMsg( "Deleting file" );
+ g_pFullFileSystem->RemoveFile( pCurFilename );
+
+ // File gone?
+ const bool bDeleted = !g_pFullFileSystem->FileExists( pCurFilename );
+ PrintEventResult( bDeleted );
+
+ // Increment # deleted if appropriate
+ if ( bDeleted )
+ {
+ ++m_nNumDeleted;
+ }
+
+ bResult = bResult && bDeleted;
+ }
+
+ return bResult ? JOB_OK : JOB_FAILED;
+}
+
+//----------------------------------------------------------------------------------------
+
+CLocalFileDeleterJob *SV_CreateLocalFileDeleterJob()
+{
+ return new CLocalFileDeleterJob();
+}
+
+
+//----------------------------------------------------------------------------------------
+
+bool SV_DoFileserverCleanup( bool bForceCleanAll, ISpewer *pSpewer )
+{
+ CServerRecordingSessionManager *pSessionManager = SV_GetRecordingSessionManager();
+ CBaseRecordingSession *pRecordingSession = SV_GetRecordingSessionInProgress();
+
+ for ( int i = 0; i < pSessionManager->Count(); )
+ {
+ CServerRecordingSession *pCurSession = SV_CastSession( SV_GetRecordingSessionManager()->m_vecObjs[ i ] );
+
+ // Skip session in progress
+ bool bRemoved = false;
+ if ( pCurSession != NULL && pCurSession != pRecordingSession )
+ {
+ // Session expired?
+ if ( bForceCleanAll || pCurSession->SessionExpired() )
+ {
+ // The session's OnDelete() will add the session file to the cleanup system,
+ // and also delete all associated blocks, whose OnDelete() will also add their
+ // associated .block files to the cleanup system.
+ pSessionManager->RemoveFromIndex( i );
+
+ bRemoved = true;
+ }
+ }
+
+ if ( !bRemoved )
+ {
+ ++i;
+ }
+ }
+
+ pSpewer->PrintBlockStart();
+
+ pSpewer->PrintMsg( "Attempting to clean up stale replay data..." );
+ pSpewer->PrintEmptyLine();
+
+ // NOTE: There may be files queued up in addition to those marked above
+ if ( !SV_GetFileserverCleaner()->HasFilesQueuedForDelete() )
+ {
+ pSpewer->PrintMsg( "No replay data to clean up." );
+ pSpewer->PrintBlockEnd();
+ }
+ else
+ {
+ // Asynchronously delete all collected files
+ SV_GetFileserverCleaner()->DoCleanAsynchronous( true, g_pBlockSpewer );
+ }
+
+ return true;
+}
+
+CBaseJob *SV_CreateDeleteFileJob()
+{
+ return SV_CreateLocalFileDeleterJob();
+}
+
+//----------------------------------------------------------------------------------------