uint32 FBuildPatchInstaller::Run() { // Make sure this function can never be parallelized static FCriticalSection SingletonFunctionLockCS; FScopeLock SingletonFunctionLock(&SingletonFunctionLockCS); FBuildPatchInstallError::Reset(); SetRunning(true); SetInited(true); SetDownloadSpeed(-1); UpdateDownloadProgressInfo(true); // Register the current manifest with the installation info, to make sure we pull from it if (CurrentBuildManifest.IsValid()) { InstallationInfo.RegisterAppInstallation(CurrentBuildManifest.ToSharedRef(), InstallDirectory); } // Keep track of files that failed verify TArray<FString> CorruptFiles; // Init prereqs progress value const bool bInstallPrereqs = !CurrentBuildManifest.IsValid() && !NewBuildManifest->GetPrereqPath().IsEmpty(); // Get the start time double StartTime = FPlatformTime::Seconds(); double CleanUpTime = 0; // Keep retrying the install while it is not canceled, or caused by download error bool bProcessSuccess = false; bool bCanRetry = true; int32 InstallRetries = 5; while (!bProcessSuccess && bCanRetry) { // Run the install bool bInstallSuccess = RunInstallation(CorruptFiles); BuildProgress.SetStateProgress(EBuildPatchProgress::PrerequisitesInstall, bInstallPrereqs ? 0.0f : 1.0f); if (bInstallSuccess) { BuildProgress.SetStateProgress(EBuildPatchProgress::Downloading, 1.0f); BuildProgress.SetStateProgress(EBuildPatchProgress::Installing, 1.0f); } // Backup local changes then move generated files bInstallSuccess = bInstallSuccess && RunBackupAndMove(); // Run Verification CorruptFiles.Empty(); BuildProgress.SetStateProgress(EBuildPatchProgress::Initializing, 1.0f); bProcessSuccess = bInstallSuccess && RunVerification(CorruptFiles); // Clean staging if INSTALL success if (bInstallSuccess) { GLog->Logf(TEXT("BuildPatchServices: Deleting staging area")); CleanUpTime = FPlatformTime::Seconds(); IFileManager::Get().DeleteDirectory(*StagingDirectory, false, true); CleanUpTime = FPlatformTime::Seconds() - CleanUpTime; } BuildProgress.SetStateProgress(EBuildPatchProgress::CleanUp, 1.0f); // Set if we can retry --InstallRetries; bCanRetry = InstallRetries > 0 && !FBuildPatchInstallError::IsInstallationCancelled() && !FBuildPatchInstallError::IsNoRetryError(); // If successful or we will retry, remove the moved files marker if (bProcessSuccess || bCanRetry) { GLog->Logf(TEXT("BuildPatchServices: Reset MM")); IFileManager::Get().Delete(*PreviousMoveMarker, false, true); } } if (bProcessSuccess) { // Run the prerequisites installer if this is our first install and the manifest has prerequisites info if (bInstallPrereqs) { // @TODO: We also want to trigger prereq install if this is an update and the prereq installer differs in the update bProcessSuccess &= RunPrereqInstaller(); } } // Set final stat values and log out results { FScopeLock Lock(&ThreadLock); bSuccess = bProcessSuccess; BuildStats.ProcessSuccess = bProcessSuccess; BuildStats.ProcessExecuteTime = (FPlatformTime::Seconds() - StartTime) - BuildStats.ProcessPausedTime; BuildStats.FailureReason = FBuildPatchInstallError::GetErrorString(); BuildStats.FailureReasonText = FBuildPatchInstallError::GetErrorText(); BuildStats.CleanUpTime = CleanUpTime; // Log stats GLog->Logf(TEXT("BuildPatchServices: Build Stat: AppName: %s"), *BuildStats.AppName); GLog->Logf(TEXT("BuildPatchServices: Build Stat: AppInstalledVersion: %s"), *BuildStats.AppInstalledVersion); GLog->Logf(TEXT("BuildPatchServices: Build Stat: AppPatchVersion: %s"), *BuildStats.AppPatchVersion); GLog->Logf(TEXT("BuildPatchServices: Build Stat: CloudDirectory: %s"), *BuildStats.CloudDirectory); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumFilesInBuild: %u"), BuildStats.NumFilesInBuild); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumFilesOutdated: %u"), BuildStats.NumFilesOutdated); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumFilesToRemove: %u"), BuildStats.NumFilesToRemove); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumChunksRequired: %u"), BuildStats.NumChunksRequired); GLog->Logf(TEXT("BuildPatchServices: Build Stat: ChunksQueuedForDownload: %u"), BuildStats.ChunksQueuedForDownload); GLog->Logf(TEXT("BuildPatchServices: Build Stat: ChunksLocallyAvailable: %u"), BuildStats.ChunksLocallyAvailable); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumChunksDownloaded: %u"), BuildStats.NumChunksDownloaded); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumChunksRecycled: %u"), BuildStats.NumChunksRecycled); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumChunksCacheBooted: %u"), BuildStats.NumChunksCacheBooted); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumDriveCacheChunkLoads: %u"), BuildStats.NumDriveCacheChunkLoads); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumRecycleFailures: %u"), BuildStats.NumRecycleFailures); GLog->Logf(TEXT("BuildPatchServices: Build Stat: NumDriveCacheLoadFailures: %u"), BuildStats.NumDriveCacheLoadFailures); GLog->Logf(TEXT("BuildPatchServices: Build Stat: TotalDownloadedData: %lld"), BuildStats.TotalDownloadedData); GLog->Logf(TEXT("BuildPatchServices: Build Stat: AverageDownloadSpeed: %.3f MB/sec"), BuildStats.AverageDownloadSpeed / 1024.0 / 1024.0); GLog->Logf(TEXT("BuildPatchServices: Build Stat: TheoreticalDownloadTime: %s"), *FPlatformTime::PrettyTime(BuildStats.TheoreticalDownloadTime)); GLog->Logf(TEXT("BuildPatchServices: Build Stat: VerifyTime: %s"), *FPlatformTime::PrettyTime(BuildStats.VerifyTime)); GLog->Logf(TEXT("BuildPatchServices: Build Stat: CleanUpTime: %s"), *FPlatformTime::PrettyTime(BuildStats.CleanUpTime)); GLog->Logf(TEXT("BuildPatchServices: Build Stat: ProcessExecuteTime: %s"), *FPlatformTime::PrettyTime(BuildStats.ProcessExecuteTime)); GLog->Logf(TEXT("BuildPatchServices: Build Stat: ProcessPausedTime: %.1f sec"), BuildStats.ProcessPausedTime); GLog->Logf(TEXT("BuildPatchServices: Build Stat: ProcessSuccess: %s"), BuildStats.ProcessSuccess ? TEXT("TRUE") : TEXT("FALSE")); GLog->Logf(TEXT("BuildPatchServices: Build Stat: FailureReason: %s"), *BuildStats.FailureReason); GLog->Logf(TEXT("BuildPatchServices: Build Stat: FailureReasonText: %s"), *BuildStats.FailureReasonText.BuildSourceString()); } // Mark that we are done SetRunning(false); return bSuccess ? 0 : 1; }
uint32 FBuildPatchFileConstructor::Run() { SetRunning( true ); SetInited( true ); const bool bIsFileData = BuildManifest->IsFileDataManifest(); // Save the list of completed files TArray< FString > ConstructedFiles; // Check for resume data FResumeData ResumeData( StagingDirectory, BuildManifest ); // Start resume progress at zero or one BuildProgress->SetStateProgress( EBuildPatchProgress::Resuming, ResumeData.bHasResumeData ? 0.0f : 1.0f ); // While we have files to construct, run FString FileToConstruct; while( GetFileToConstruct( FileToConstruct ) && !FBuildPatchInstallError::HasFatalError() ) { // Check resume status, currently we are only supporting sequential resume, so once we start downloading, we can't resume any more. // this only comes up if the resume data has been changed externally. ResumeData.CheckFile( FileToConstruct ); const bool bFilePreviouslyComplete = !bIsDownloadStarted && ResumeData.FilesCompleted.Contains( FileToConstruct ); const bool bFilePreviouslyStarted = !bIsDownloadStarted && ResumeData.FilesStarted.Contains( FileToConstruct ); // Construct or skip the file bool bFileSuccess; if( bFilePreviouslyComplete ) { bFileSuccess = true; CountBytesProcessed( BuildManifest->GetFileSize( FileToConstruct ) ); // Inform the chunk cache of the chunk skip if( !bIsFileData ) { FBuildPatchChunkCache::Get().SkipFile( FileToConstruct ); } } else { bFileSuccess = ConstructFileFromChunks( FileToConstruct, bFilePreviouslyStarted ); // Add to resume data if successful or failure was not file construction fail if( bFileSuccess || FBuildPatchInstallError::GetErrorState() != EBuildPatchInstallError::FileConstructionFail ) { ResumeData.FilesStarted.AddUnique( FileToConstruct ); } } // If the file succeeded, add to lists if( bFileSuccess ) { ConstructedFiles.Add( FileToConstruct ); } else { GWarn->Logf( TEXT( "BuildPatchServices: ERROR: Failed to construct file %s" ), *FPaths::GetCleanFilename( FileToConstruct ) ); FBuildPatchInstallError::SetFatalError( EBuildPatchInstallError::FileConstructionFail ); } // Pause BuildProgress->WaitWhilePaused(); } // Save resume data ResumeData.SaveOut(); BuildProgress->SetStateProgress(EBuildPatchProgress::Resuming, 1.0f); // Set constructed files ThreadLock.Lock(); FilesConstructed.Empty(); FilesConstructed.Append( ConstructedFiles ); ThreadLock.Unlock(); SetRunning( false ); return 0; }