You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb Per.Larsson #rnx #preflight 60f9212d1f926d0001d41223 * VirtualizationJupiterBackend - When pulling a payload we should assume that a 400 error response when trying to GET the payload header means that the payload is not in Jupiter. -- Not being able to find the payload should not log an error, instead we can make a note of it in the verbose log (similar to the file system backend) * VirtualizationFileBackend - Moved the formatting of system errors to it's own function. - Log the system error when failing to write a payload during a push as well as a pull. - We now check that the FileArchive wrote correctly to disk and delete the output file and fail the push if it did not. -- A future piece of work will change the logic to write to a tmp file at the root of the file store and them move the file to the final location to cut down on the potential of leaving corrupted files around (similar to the process when we save packages) * Perforce - The FDownloadFile command now takes an optional parameter EVerbosity that can allow the caller to choose the level of logging output that the command will generate. - The source control backend for Mirage now opts to supress the logging of the full perforce command when we are pulling payloads as we can generate many hundreds or thousands of requests and the info is not useful to users. -- We continue to log the command when validating the depot as this is the most likely command to fail so having the info in the log may prove useful. #ROBOMERGE-SOURCE: CL 16921815 in //UE5/Main/... #ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v836-16769935) [CL 16921818 by paul chipchase in ue5-release-engine-test branch]
193 lines
5.9 KiB
C++
193 lines
5.9 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Virtualization/IVirtualizationBackend.h"
|
|
|
|
#include "Containers/StringView.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/Parse.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/StringBuilder.h"
|
|
#include "Virtualization/VirtualizationManager.h"
|
|
#include "VirtualizationUtilities.h"
|
|
|
|
namespace UE::Virtualization
|
|
{
|
|
/**
|
|
* Fill in the given string builder with the human readable message of the current system
|
|
* code, followed by the code value itself.
|
|
* In the system value is currently 0, then we assume that it was cleared before this was
|
|
* able to be called and write that the error is unknown instead of assuming that the
|
|
* operation was a success.
|
|
*/
|
|
void GetFormattedSystemError(FStringBuilderBase& SystemErrorMessage)
|
|
{
|
|
SystemErrorMessage.Reset();
|
|
|
|
const uint32 SystemError = FPlatformMisc::GetLastError();
|
|
// If we have a system error we can give a more informative error message but don't output it if the error is zero as
|
|
// this can lead to very confusing error messages.
|
|
if (SystemError != 0)
|
|
{
|
|
TCHAR SystemErrorMsg[MAX_SPRINTF] = { 0 };
|
|
FPlatformMisc::GetSystemErrorMessage(SystemErrorMsg, sizeof(SystemErrorMsg), SystemError);
|
|
|
|
SystemErrorMessage.Appendf(TEXT("'%s' (%d)"), SystemErrorMsg, SystemError);
|
|
}
|
|
else
|
|
{
|
|
SystemErrorMessage << TEXT("'unknown reason' (0)");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A basic backend based on the file system. This can be used to access/store virtualization
|
|
* data either on a local disk or a network share. It is intended to be used as a caching system
|
|
* to speed up operations (running a local cache or a shared cache for a site) rather than as the
|
|
* proper backend solution.
|
|
*
|
|
* Ini file setup:
|
|
* 'Name'=(Type=FileSystem, Path="XXX")
|
|
* Where 'Name' is the backend name in the hierarchy and 'XXX' if the path to the directory where
|
|
* you want to files to be stored.
|
|
*/
|
|
class FFileSystemBackend : public IVirtualizationBackend
|
|
{
|
|
public:
|
|
FFileSystemBackend(FStringView ConfigName)
|
|
: IVirtualizationBackend(EOperations::Both)
|
|
{
|
|
Name = WriteToString<256>(TEXT("FFileSystemBackend - "), ConfigName).ToString();
|
|
}
|
|
|
|
virtual ~FFileSystemBackend() = default;
|
|
|
|
private:
|
|
|
|
virtual bool Initialize(const FString& ConfigEntry) override
|
|
{
|
|
if (!FParse::Value(*ConfigEntry, TEXT("Path="), RootDirectory))
|
|
{
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] 'Path=' not found in the config file"), *GetDebugString());
|
|
return false;
|
|
}
|
|
|
|
FPaths::NormalizeDirectoryName(RootDirectory);
|
|
|
|
if (RootDirectory.IsEmpty())
|
|
{
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] Config file entry 'Path=' was empty"), *GetDebugString());
|
|
return false;
|
|
}
|
|
|
|
// TODO: Validate that the given path is usable?
|
|
|
|
UE_LOG(LogVirtualization, Log, TEXT("[%s] Using path: '%s'"), *GetDebugString(), *RootDirectory);
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual EPushResult PushData(const FPayloadId& Id, const FCompressedBuffer& Payload) override
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::PushData);
|
|
|
|
if (DoesExist(Id))
|
|
{
|
|
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Already has a copy of the payload '%s'."), *GetDebugString(), *Id.ToString());
|
|
return EPushResult::PayloadAlreadyExisted;
|
|
}
|
|
|
|
TStringBuilder<512> FilePath;
|
|
CreateFilePath(Id, FilePath);
|
|
|
|
// TODO: Should we write to a temp file and then move it once it has written?
|
|
TUniquePtr<FArchive> FileAr(IFileManager::Get().CreateFileWriter(FilePath.ToString()));
|
|
|
|
if (FileAr == nullptr)
|
|
{
|
|
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
|
|
GetFormattedSystemError(SystemErrorMsg);
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to write payload '%s' to '%s' due to system error: %s"), *GetDebugString(), *Id.ToString(), FilePath.ToString(), SystemErrorMsg.ToString());
|
|
|
|
return EPushResult::Failed;
|
|
}
|
|
|
|
for (const FSharedBuffer& Buffer : Payload.GetCompressed().GetSegments())
|
|
{
|
|
// Const cast because FArchive requires a non-const pointer!
|
|
FileAr->Serialize(const_cast<void*>(Buffer.GetData()), static_cast<int64>(Buffer.GetSize()));
|
|
}
|
|
|
|
if (FileAr->Close())
|
|
{
|
|
return EPushResult::Success;
|
|
}
|
|
else
|
|
{
|
|
// TODO: If we were first saving to a tmp file we could avoid the need to delete the
|
|
// potentially corrupt output file.
|
|
IFileManager::Get().Delete(FilePath.ToString());
|
|
return EPushResult::Failed;
|
|
}
|
|
}
|
|
|
|
virtual FCompressedBuffer PullData(const FPayloadId& Id) override
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::PullData);
|
|
|
|
TStringBuilder<512> FilePath;
|
|
CreateFilePath(Id, FilePath);
|
|
|
|
// TODO: Should we allow the error severity to be configured via ini or just not report this case at all?
|
|
if (!IFileManager::Get().FileExists(FilePath.ToString()))
|
|
{
|
|
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Does not contain the payload '%s'"), *GetDebugString(), *Id.ToString());
|
|
return FCompressedBuffer();
|
|
}
|
|
|
|
TUniquePtr<FArchive> FileAr(IFileManager::Get().CreateFileReader(FilePath.ToString()));
|
|
if (FileAr == nullptr)
|
|
{
|
|
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
|
|
GetFormattedSystemError(SystemErrorMsg);
|
|
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to load payload '%s' from file '%s' due to system error: %s"), *GetDebugString(), *Id.ToString(), FilePath.ToString(), SystemErrorMsg.ToString());
|
|
|
|
return FCompressedBuffer();
|
|
}
|
|
|
|
return FCompressedBuffer::FromCompressed(*FileAr);
|
|
}
|
|
|
|
bool DoesExist(const FPayloadId& Id)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::DoesExist);
|
|
|
|
TStringBuilder<512> FilePath;
|
|
CreateFilePath(Id, FilePath);
|
|
|
|
return IFileManager::Get().FileExists(FilePath.ToString());
|
|
}
|
|
|
|
virtual FString GetDebugString() const override
|
|
{
|
|
return Name;
|
|
}
|
|
|
|
void CreateFilePath(const FPayloadId& PayloadId, FStringBuilderBase& OutPath)
|
|
{
|
|
TStringBuilder<52> PayloadPath;
|
|
Utils::PayloadIdToPath(PayloadId, PayloadPath);
|
|
|
|
OutPath << RootDirectory << TEXT("/") << PayloadPath;
|
|
}
|
|
|
|
private:
|
|
|
|
FString Name;
|
|
FString RootDirectory;
|
|
};
|
|
|
|
UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY(FFileSystemBackend, FileSystem);
|
|
|
|
} // namespace UE::Virtualization
|