261 lines
6.2 KiB
C++
261 lines
6.2 KiB
C++
|
//========= 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();
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|