Files
UnrealEngineUWP/Engine/Source/Developer/Virtualization/Private/VirtualizationFileBackend.cpp

283 lines
8.5 KiB
C++
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
#include "VirtualizationFileBackend.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformProcess.h"
#include "Misc/Parse.h"
#include "Misc/Paths.h"
#include "VirtualizationUtilities.h"
namespace UE::Virtualization
{
FFileSystemBackend::FFileSystemBackend(FStringView ProjectName, FStringView ConfigName, FStringView DebugName)
: IVirtualizationBackend(ConfigName, DebugName, EOperations::Push | EOperations::Pull)
{
}
bool FFileSystemBackend::Initialize(const FString& ConfigEntry)
{
if (!FParse::Value(*ConfigEntry, TEXT("Path="), RootDirectory))
{
RootDirectory = *WriteToString<512>(FPaths::ProjectSavedDir(), TEXT("VAPayloads"));
}
FString EnvOverrideName;
if (FParse::Value(*ConfigEntry, TEXT("EnvPathOverride="), EnvOverrideName))
{
FString OverridePath = FPlatformMisc::GetEnvironmentVariable(*EnvOverrideName);
if (!OverridePath.IsEmpty())
{
UE_LOG(LogVirtualization, Log, TEXT("[%s] Overriding path with envvar '%s'"), *GetDebugName(), *EnvOverrideName);
RootDirectory = OverridePath;
}
}
FPaths::NormalizeDirectoryName(RootDirectory);
if (RootDirectory.IsEmpty())
{
UE_LOG(LogVirtualization, Error, TEXT("[%s] Config file entry 'Path=' was empty"), *GetDebugName());
return false;
}
// TODO: Validate that the given path is usable?
int32 RetryCountIniFile = INDEX_NONE;
if (FParse::Value(*ConfigEntry, TEXT("RetryCount="), RetryCountIniFile))
{
RetryCount = RetryCountIniFile;
}
int32 RetryWaitTimeMSIniFile = INDEX_NONE;
if (FParse::Value(*ConfigEntry, TEXT("RetryWaitTime="), RetryWaitTimeMSIniFile))
{
RetryWaitTimeMS = RetryWaitTimeMSIniFile;
}
// Now log a summary of the backend settings to make issues easier to diagnose
UE_LOG(LogVirtualization, Log, TEXT("[%s] Using path: '%s'"), *GetDebugName(), *FPaths::ConvertRelativePathToFull(RootDirectory));
UE_LOG(LogVirtualization, Log, TEXT("[%s] Will retry failed read attempts %d times with a gap of %dms betwen them"), *GetDebugName(), RetryCount, RetryWaitTimeMS);
return true;
}
Add a number of ways for the VA backend connections to be changed to lazy initialize on first use. #rb Devin.Doucette #jira UE-161599 #rnx #preflight 6303c8d65a5d4e4624e7bf52 - There are some use cases that require the VA system to be initialized and configured correctly but would prefer that the backend connections only run if absolutely needed (usually when a payload is pulled or pushed for the first time), this change provides four different ways of doing this: -- Setting [Core.VirtualizationModule]LazyInitConnections=true in the Engine ini file -- Setting the define 'UE_VIRTUALIZATION_CONNECTION_LAZY_INIT' to 1 in a programs .target.cs -- Running with the commandline option -VA-LazyInitConnections -- Setting the cvar 'VA.LazyInitConnections' to 1 (only works if it is set before the VA system is initialized, changing it mid editor via the console does nothing) --- Note that after the config file, each setting there only opts into lazy initializing the connections, setting the cvar to 0 for example will not prevent the cmdline from opting in etc. - In the future we will allow the connection code to run async, so the latency can be hidden behind the editor loading, but for the current use case we are taking the minimal approach. -- This means we only support the backend being in 3 states. No connection has been made yet, the connection is broken and the connection is working. -- To keep things simple we only record if we have attempted to connect the backends or not. We don't check individual backends nor do we try to reconnect failed ones etc. This is all scheduled for a future work item. - If the connections are not initialized when the VA system is, we wait until the first time someone calls one of the virtualization methods that will actually use a connection: Push/Pull/Query -- We try connecting all of the backends at once, even if they won't be used in the call to keep things simple. - Only the source control backend makes use of the connection system. The horde storage (http) backend could take advantage too, but it is currently unused and most likely going to just be deleted so there seemed little point updating it. - If we try to run an operation on an unconnected backend we only log to verbose. This is to maintain existing behaviour where a failed backend would not be mounted at all. This logging will likely be revisited in a future work item. [CL 21511855 by paul chipchase in ue5-main branch]
2022-08-23 13:01:15 -04:00
IVirtualizationBackend::EConnectionStatus FFileSystemBackend::OnConnect()
{
return IVirtualizationBackend::EConnectionStatus::Connected;
}
bool FFileSystemBackend::PushData(TArrayView<FPushRequest> Requests, EPushFlags Flags)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::PushData);
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
int32 ErrorCount = 0;
const bool bEnableExistenceCheck = !EnumHasAllFlags(Flags, EPushFlags::Force);
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
for (FPushRequest& Request : Requests)
{
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
const FIoHash& PayloadId = Request.GetIdentifier();
if (bEnableExistenceCheck && DoesPayloadExist(PayloadId))
{
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Already has a copy of the payload '%s'."), *GetDebugName(), *LexToString(PayloadId));
Request.SetResult(FPushResult::GetAsAlreadyExists());
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
continue;
}
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
// Make sure to log any disk write failures to the user, even if this backend will often be optional as they are
// not expected and could indicate bigger problems.
//
// First we will write out the payload to a temp file, after which we will move it to the correct storage location
// this helps reduce the chance of leaving corrupted data on disk in the case of a power failure etc.
const FString TempFilePath = FPaths::CreateTempFilename(*FPaths::ProjectSavedDir(), TEXT("vapayload"));
TUniquePtr<FArchive> FileAr(IFileManager::Get().CreateFileWriter(*TempFilePath));
if (FileAr == nullptr)
{
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
Utils::GetFormattedSystemError(SystemErrorMsg);
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to write payload '%s' to '%s' due to system error: %s"),
*GetDebugName(),
*LexToString(PayloadId),
*TempFilePath,
SystemErrorMsg.ToString());
ErrorCount++;
Request.SetResult(FPushResult::GetAsError());
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
continue;
}
{
FCompressedBuffer Payload = Request.GetPayload();
*FileAr << Payload;
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
}
if (!FileAr->Close())
{
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
Utils::GetFormattedSystemError(SystemErrorMsg);
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to write payload '%s' contents to '%s' due to system error: %s"),
*GetDebugName(),
*LexToString(PayloadId),
*TempFilePath,
SystemErrorMsg.ToString());
IFileManager::Get().Delete(*TempFilePath, true, false, true); // Clean up the temp file if it is still around but do not failure cases to the user
ErrorCount++;
Request.SetResult(FPushResult::GetAsError());
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
continue;
}
TStringBuilder<512> FilePath;
CreateFilePath(PayloadId, FilePath);
// If the file already exists we don't need to replace it, we will also do our own error logging.
if (IFileManager::Get().Move(FilePath.ToString(), *TempFilePath, /*Replace*/ false, /*EvenIfReadOnly*/ false, /*Attributes*/ false, /*bDoNotRetryOrError*/ true))
{
Request.SetResult(FPushResult::GetAsPushed());
}
else
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
{
// Store the error message in case we need to display it
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
Utils::GetFormattedSystemError(SystemErrorMsg);
IFileManager::Get().Delete(*TempFilePath, true, false, true); // Clean up the temp file if it is still around but do not failure cases to the user
// Check if another thread or process was writing out the payload at the same time, if so we
// don't need to give an error message.
if (DoesPayloadExist(PayloadId))
{
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Already has a copy of the payload '%s'."), *GetDebugName(), *LexToString(PayloadId));
Request.SetResult(FPushResult::GetAsAlreadyExists());
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
continue;
}
else
{
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to move payload '%s' to it's final location '%s' due to system error: %s"),
*GetDebugName(),
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
*LexToString(PayloadId),
*FilePath,
SystemErrorMsg.ToString());
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
ErrorCount++;
Request.SetResult(FPushResult::GetAsError());
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
}
}
}
Refactor the VA pushing API so that we only need to implement a single path #rb Per.Larsson #jira UE-163103 #rnx #preflight 6318989c2b7fe03eb664e9f0 ### VirtualizationSystem/VirtualizationManager - Added an overload of ::Push taking just one FPUshRequest so that people don't have to keep adding MakeArrayView boiler plate when pushing a single request - Change the order of the last two parameters for the raw ::Push call as this will group all of the payload specific parameters together and leave the target storage type at the end. It is unlikely that anyone is calling the older version but it has been deprecated for safety. ### IVirtualizationBackend - The none FPushRequest overload of ::PushData is no longer virtual, it just converts the parameters to FPushRequest and calls that overload instead. In this way we now only have one pushing code path in our backends. We could probably look into removing this overload at this point (since the higher level IVirtualizationSystem will now convert all push requests into a FPushRequest form) but it is not considered worth it at the moment when the simple overload covers our needs. - Removed EPushResult in favour of just returning true/false for the overall operation.If the caller needs a more detailed breakdown then they will have to use an overload that takes an FPushRequest over raw parameters. -- At the moment FPushRequest does not contain a full breakdown of what happened, so with this submit we are effectively losing the ability to find out if the payload was already in the backends or not, however the batch version of push was already not returning this info so it is not a big loss. Fixing FPushRequest to return a better break down of what happened will be done in UE-160942 - Removed the none batch Push paths from the source control and ddc backends as they already supported batch pushing. - File backend needed to be converted to supporting batch pushing, which is pretty much the same code as before except we need to iterate over the container of FPushRequests. -- The backend does not early out on error as it tends to be quite fast. We might want to consider an official policy for the VA system, if we should early out of errors or not. [CL 21907558 by paul chipchase in ue5-main branch]
2022-09-08 19:35:36 -04:00
return ErrorCount == 0;
}
bool FFileSystemBackend::PullData(TArrayView<FPullRequest> Requests, EPullFlags Flags, FText& OutErrors)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::PullData);
for (FPullRequest& Request : Requests)
{
TStringBuilder<512> FilePath;
CreateFilePath(Request.GetIdentifier(), 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'"),
*GetDebugName(),
*LexToString(Request.GetIdentifier()));
continue;
}
TUniquePtr<FArchive> FileAr = OpenFileForReading(FilePath.ToString());
if (FileAr == nullptr)
{
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
Utils::GetFormattedSystemError(SystemErrorMsg);
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to load payload '%s' from file '%s' due to system error: %s"),
*GetDebugName(),
*LexToString(Request.GetIdentifier()),
FilePath.ToString(),
SystemErrorMsg.ToString());
Request.SetError();
continue;
}
Request.SetPayload(FCompressedBuffer::Load(*FileAr));
if (FileAr->IsError())
{
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to serialize payload '%s' from file '%s'"),
*GetDebugName(),
*LexToString(Request.GetIdentifier()),
FilePath.ToString());
Request.SetError();
continue;
}
}
return true;
}
bool FFileSystemBackend::DoesPayloadExist(const FIoHash& Id)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::DoesPayloadExist);
TStringBuilder<512> FilePath;
CreateFilePath(Id, FilePath);
return IFileManager::Get().FileExists(FilePath.ToString());
}
void FFileSystemBackend::CreateFilePath(const FIoHash& PayloadId, FStringBuilderBase& OutPath)
{
TStringBuilder<52> PayloadPath;
Utils::PayloadIdToPath(PayloadId, PayloadPath);
OutPath << RootDirectory << TEXT("/") << PayloadPath;
}
TUniquePtr<FArchive> FFileSystemBackend::OpenFileForReading(const TCHAR* FilePath)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::OpenFileForReading);
int32 Retries = 0;
while (Retries < RetryCount)
{
TUniquePtr<FArchive> FileAr(IFileManager::Get().CreateFileReader(FilePath));
if (FileAr)
{
return FileAr;
}
else
{
UE_LOG(LogVirtualization, Warning, TEXT("[%s] Failed to open '%s' for reading attempt retrying (%d/%d) in %dms..."), *GetDebugName(), FilePath, Retries, RetryCount, RetryWaitTimeMS);
FPlatformProcess::SleepNoStats(static_cast<float>(RetryWaitTimeMS) * 0.001f);
Retries++;
}
}
return nullptr;
}
UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY(FFileSystemBackend, FileSystem);
} // namespace UE::Virtualization