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 #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]
319 lines
12 KiB
C++
319 lines
12 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Compression/CompressedBuffer.h"
|
|
#include "Containers/StringView.h"
|
|
#include "Features/IModularFeature.h"
|
|
#include "Features/IModularFeatures.h"
|
|
#include "Templates/UniquePtr.h"
|
|
#include "Virtualization/VirtualizationSystem.h"
|
|
|
|
struct FIoHash;
|
|
|
|
namespace UE::Virtualization
|
|
{
|
|
|
|
/**
|
|
* The interface to derive from to create a new backend implementation.
|
|
*
|
|
* Note that virtualization backends are instantiated FVirtualizationManager via
|
|
* IVirtualizationBackendFactory so each new backend derived from IVirtualizationBackend
|
|
* will also need a factory derived from IVirtualizationBackendFactory. You can either do
|
|
* this manually or use the helper macro 'UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY' to
|
|
* generate the code for you.
|
|
*
|
|
*/
|
|
class IVirtualizationBackend
|
|
{
|
|
public:
|
|
/** Enum detailing which operations a backend can support */
|
|
enum class EOperations : uint8
|
|
{
|
|
/** Supports no operations, this should only occur when debug settings are applied */
|
|
None = 0,
|
|
/** Supports only push operations */
|
|
Push = 1 << 0,
|
|
/** Supports only pull operations */
|
|
Pull = 1 << 1,
|
|
};
|
|
|
|
FRIEND_ENUM_CLASS_FLAGS(EOperations);
|
|
|
|
/** Status of the backends connection to its services */
|
|
enum class EConnectionStatus
|
|
{
|
|
/** No connection attempt has been made */
|
|
None,
|
|
/** The previous connection attempt ended with an error */
|
|
Error,
|
|
/** The connection has been made successfully */
|
|
Connected,
|
|
};
|
|
|
|
protected:
|
|
|
|
IVirtualizationBackend(FStringView InConfigName, FStringView InDebugName, EOperations InSupportedOperations)
|
|
: SupportedOperations(InSupportedOperations)
|
|
, DebugDisabledOperations(EOperations::None)
|
|
, ConfigName(InConfigName)
|
|
, DebugName(InDebugName)
|
|
{
|
|
checkf(InSupportedOperations != EOperations::None, TEXT("Cannot create a backend with no supported operations!"));
|
|
}
|
|
|
|
public:
|
|
virtual ~IVirtualizationBackend() = default;
|
|
|
|
/**
|
|
* This will be called during the setup of the backend hierarchy. The entry config file
|
|
* entry that caused the backend to be created will be passed to the method so that any
|
|
* additional settings may be parsed from it.
|
|
* Take care to clearly log any error that occurs so that the end user has a clear way
|
|
* to fix them.
|
|
*
|
|
* @param ConfigEntry The entry for the backend from the config ini file that may
|
|
* contain additional settings.
|
|
* @return Returning false indicates that initialization failed in a way
|
|
* that the backend will not be able to function correctly.
|
|
*/
|
|
virtual bool Initialize(const FString& ConfigEntry) = 0;
|
|
|
|
/**
|
|
* Attempt to connect the backend to its services if not already connected.
|
|
*/
|
|
virtual void Connect()
|
|
{
|
|
if (ConnectionStatus != EConnectionStatus::Connected)
|
|
{
|
|
ConnectionStatus = OnConnect();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the connection status of the backend
|
|
*
|
|
* @return @see EConnectionStatus
|
|
*/
|
|
EConnectionStatus GetConnectionStatus() const
|
|
{
|
|
return ConnectionStatus;
|
|
}
|
|
|
|
/**
|
|
* The backend will attempt to store the given payload by what ever method the backend uses.
|
|
* NOTE: It is assumed that the virtualization manager will run all appropriate validation
|
|
* on the payload and it's id and that the inputs to PushData can be trusted.
|
|
*
|
|
* @param Id The Id of the payload
|
|
* @param Payload A potentially compressed buffer representing the payload
|
|
* @return The result of the push operation
|
|
*/
|
|
bool PushData(const FIoHash& Id, const FCompressedBuffer& Payload, const FString& PackageContext)
|
|
{
|
|
FPushRequest Request(Id, Payload, PackageContext);
|
|
|
|
return PushData(MakeArrayView(&Request, 1));
|
|
}
|
|
|
|
/**
|
|
* @return True if all of the requests succeeded, false if one of more failed
|
|
*/
|
|
virtual bool PushData(TArrayView<FPushRequest> Requests) = 0;
|
|
|
|
/**
|
|
* The backend will attempt to retrieve the given payload by what ever method the backend uses.
|
|
* NOTE: It is assumed that the virtualization manager will validate the returned payload to
|
|
* make sure that it matches the requested id so there is no need for each backend to do this/
|
|
*
|
|
* @param Id The Id of a payload to try and pull from the backend.
|
|
*
|
|
* @return A valid FCompressedBuffer containing the payload if the pull
|
|
* operation succeeded and a null FCompressedBuffer
|
|
* if it did not.
|
|
*/
|
|
virtual FCompressedBuffer PullData(const FIoHash& Id) = 0;
|
|
|
|
/**
|
|
* Checks if a payload exists in the backends storage.
|
|
*
|
|
* @param Id The identifier of the payload to check
|
|
*
|
|
* @return True if the backend storage already contains the payload, otherwise false
|
|
*/
|
|
virtual bool DoesPayloadExist(const FIoHash& Id) = 0;
|
|
|
|
/**
|
|
* Checks if a number of payload exists in the backends storage.
|
|
*
|
|
* @param[in] PayloadIds An array of FIoHash that should be checked
|
|
* @param[out] OutResults An array to contain the result, true if the payload
|
|
* exists in the backends storage, false if not.
|
|
* This array will be resized to match the size of PayloadIds.
|
|
*
|
|
* @return True if the operation completed without error, otherwise false
|
|
*/
|
|
virtual bool DoPayloadsExist(TArrayView<const FIoHash> PayloadIds, TArray<bool>& OutResults)
|
|
{
|
|
// This is the default implementation that just calls ::DoesExist on each FIoHash in the
|
|
// array, one at a time.
|
|
// Backends may override this with their own implementations if it can be done with less
|
|
// overhead by performing the check on the entire batch instead.
|
|
|
|
OutResults.SetNum(PayloadIds.Num());
|
|
|
|
for (int32 Index = 0; Index < PayloadIds.Num(); ++Index)
|
|
{
|
|
OutResults[Index] = DoesPayloadExist(PayloadIds[Index]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given operation is supported, this is set when the backend is created
|
|
* and should not change over it's life time.
|
|
*/
|
|
bool IsOperationSupported(EOperations Operation) const
|
|
{
|
|
return EnumHasAnyFlags(SupportedOperations, Operation);
|
|
}
|
|
|
|
/** Enable or disable the given operation based on the 'bIsDisabled' parameter */
|
|
void SetOperationDebugState(EOperations Operation, bool bIsDisabled)
|
|
{
|
|
if (bIsDisabled)
|
|
{
|
|
EnumAddFlags(DebugDisabledOperations, Operation);
|
|
|
|
}
|
|
else
|
|
{
|
|
EnumRemoveFlags(DebugDisabledOperations, Operation);
|
|
}
|
|
}
|
|
|
|
/** Returns true if the given operation is disabled for debugging purposes */
|
|
bool IsOperationDebugDisabled(EOperations Operation) const
|
|
{
|
|
return EnumHasAnyFlags(DebugDisabledOperations, Operation);
|
|
}
|
|
|
|
/** Returns a string containing the name of the backend as it appears in the virtualization graph in the config file */
|
|
const FString& GetConfigName() const
|
|
{
|
|
return ConfigName;
|
|
}
|
|
|
|
/** Returns a string that can be used to identify the backend for debugging and logging purposes */
|
|
const FString& GetDebugName() const
|
|
{
|
|
return DebugName;
|
|
}
|
|
|
|
private:
|
|
|
|
/** Override to implement the backends connection code */
|
|
virtual EConnectionStatus OnConnect() = 0;
|
|
|
|
private:
|
|
|
|
/** The operations that this backend supports */
|
|
EOperations SupportedOperations;
|
|
|
|
EOperations DebugDisabledOperations;
|
|
|
|
/** The name assigned to the backend by the virtualization graph */
|
|
FString ConfigName;
|
|
|
|
/** Combination of the backend type and the name used to create it in the virtualization graph */
|
|
FString DebugName;
|
|
|
|
/** The status of the connection to the backends service */
|
|
EConnectionStatus ConnectionStatus = EConnectionStatus::None;
|
|
};
|
|
|
|
/**
|
|
* Derive from this interface to implement a factory to return a backend type.
|
|
* An instance of the factory should be created and then registered to
|
|
* IModularFeatures with the feature name "VirtualizationBackendFactory" to
|
|
* give 'FVirtualizationManager' access to it.
|
|
* The macro 'UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY' can be used to create
|
|
* a factory easily if you do not want to specialize the behaviour.
|
|
*/
|
|
class IVirtualizationBackendFactory : public IModularFeature
|
|
{
|
|
public:
|
|
/**
|
|
* Creates a new backend instance.
|
|
*
|
|
* @param ProjectName The name of the current project
|
|
* @param ConfigName The name given to the back end in the config ini file
|
|
* @return A new backend instance
|
|
*/
|
|
virtual TUniquePtr<IVirtualizationBackend> CreateInstance(FStringView ProjectName, FStringView ConfigName) = 0;
|
|
|
|
/** Returns the name used to identify the type in config ini files */
|
|
virtual FName GetName() = 0;
|
|
};
|
|
|
|
ENUM_CLASS_FLAGS(IVirtualizationBackend::EOperations);
|
|
|
|
/**
|
|
* This macro is used to generate a backend factories boilerplate code if you do not
|
|
* need anything more than the default behavior.
|
|
* As well as creating the class, a single instance will be created which will register the factory with
|
|
* 'IModularFeatures' so that it is ready for use.
|
|
*
|
|
* @param BackendClass The name of the class derived from 'IVirtualizationBackend' that the factory should create
|
|
* @param The name used in config ini files to reference this backend type.
|
|
*/
|
|
#define UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY(BackendClass, ConfigName) \
|
|
class F##BackendClass##Factory : public IVirtualizationBackendFactory \
|
|
{ \
|
|
public: \
|
|
F##BackendClass##Factory() { IModularFeatures::Get().RegisterModularFeature(FName("VirtualizationBackendFactory"), this); }\
|
|
virtual ~F##BackendClass##Factory() { IModularFeatures::Get().UnregisterModularFeature(FName("VirtualizationBackendFactory"), this); } \
|
|
private: \
|
|
virtual TUniquePtr<IVirtualizationBackend> CreateInstance(FStringView ProjectName, FStringView ConfigName) override \
|
|
{ \
|
|
return MakeUnique<BackendClass>(ProjectName, ConfigName, WriteToString<256>(#ConfigName, TEXT(" - "), ConfigName).ToString()); \
|
|
} \
|
|
virtual FName GetName() override { return FName(#ConfigName); } \
|
|
}; \
|
|
static F##BackendClass##Factory BackendClass##Factory##Instance;
|
|
|
|
#define UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY_LEGACY_IMPL(FactoryName, BackendClass, LegacyConfigName, ConfigName) \
|
|
class F##FactoryName : public IVirtualizationBackendFactory \
|
|
{ \
|
|
public: \
|
|
F##FactoryName(const TCHAR* InLegacyConfigName, const TCHAR* InNewConfigName) \
|
|
: StoredLegacyConfigName(InLegacyConfigName) \
|
|
, StoredNewConfigName(InNewConfigName) \
|
|
{ IModularFeatures::Get().RegisterModularFeature(FName("VirtualizationBackendFactory"), this); }\
|
|
virtual ~F##FactoryName() { IModularFeatures::Get().UnregisterModularFeature(FName("VirtualizationBackendFactory"), this); } \
|
|
private: \
|
|
virtual TUniquePtr<IVirtualizationBackend> CreateInstance(FStringView ProjectName, FStringView ConfigName) override \
|
|
{ \
|
|
UE_LOG(LogVirtualization, Warning, TEXT("Creating a backend via the legacy config name '%s' use '%s' instead"), *StoredLegacyConfigName, *StoredNewConfigName); \
|
|
return MakeUnique<BackendClass>(ProjectName, ConfigName, WriteToString<256>(#ConfigName, TEXT(" - "), ConfigName).ToString()); \
|
|
} \
|
|
virtual FName GetName() override { return FName(#LegacyConfigName); } \
|
|
FString StoredLegacyConfigName; \
|
|
FString StoredNewConfigName;\
|
|
}; \
|
|
static F##FactoryName FactoryName##Instance(TEXT(#LegacyConfigName), TEXT(#ConfigName));
|
|
|
|
/**
|
|
* This macro can be used to change the config name used to create backends while allowing older config file entries to continue working.
|
|
* If this factory is used to instantiate a backend then we will log a warning to the user so that they can update their config file.
|
|
*
|
|
* @param BackendClass The name of the class derived from 'IVirtualizationBackend' that the factory should create.
|
|
* @param LegacyConfigName The old name that 'ConfigName' is now replacing.
|
|
* @param ConfigName The name used in config ini files to reference this backend type.
|
|
*/
|
|
#define UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY_LEGACY(BackendClass, LegacyConfigName, ConfigName) \
|
|
UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY_LEGACY_IMPL(BackendClass##LegacyConfigName##To##ConfigName##Factory, BackendClass, LegacyConfigName, ConfigName)
|
|
|
|
} // namespace UE::Virtualization
|