Files
UnrealEngineUWP/Engine/Source/Developer/Virtualization/Private/VirtualizationDDCBackend.cpp
paul chipchase 7fce632c30 Add a new backend to Mirage that uses DDC2 as the storage mechanism.
#rb Devin.Doucette
#rnx
#preflight 61307f101a52e20001978a10

- This backend replaces the plans for a backend that interfaces with Zen directly.
- The backend has no real context for each payload being pushed at the moment, for now we pass in a dummy string.
- Currently we make blocking calls to the cache. When making the initial push to local storage this is desired as it will take place during package save. However both pulling the payload and making the submission to persistent storage should be able to be made async in the future.
- The storage policy is currently exposed via the ini file for now. We might want to enforce policies for this at a later time.

#ROBOMERGE-SOURCE: CL 17416948 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v865-17346139)

[CL 17416956 by paul chipchase in ue5-release-engine-test branch]
2021-09-03 02:57:01 -04:00

191 lines
5.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "VirtualizationDDCBackend.h"
#include "Misc/Parse.h"
#include "Virtualization/PayloadId.h"
#include "DerivedDataCache.h"
#include "DerivedDataCacheRecord.h"
#include "DerivedDataRequestOwner.h"
namespace UE::Virtualization
{
/** Utility function to help convert from UE::Virtualization types to UE::DerivedData::FPayload */
UE::DerivedData::FPayload ToDDCPayload(const FPayloadId& Id, const FCompressedBuffer& Payload)
{
UE::DerivedData::FPayloadId DDCPayloadId = UE::DerivedData::FPayloadId::FromHash(Id.GetIdentifier());
return UE::DerivedData::FPayload(DDCPayloadId, Payload);
}
FDDCBackend::FDDCBackend(FStringView ConfigName)
: IVirtualizationBackend(EOperations::Both)
, BucketName(TEXT("BulkData"))
, TransferPolicy(UE::DerivedData::ECachePolicy::None)
, QueryPolicy(UE::DerivedData::ECachePolicy::None)
{
DebugName = WriteToString<256>(TEXT("FDDCBackend - "), ConfigName);
}
bool FDDCBackend::Initialize(const FString& ConfigEntry)
{
TRACE_CPUPROFILER_EVENT_SCOPE(Initialize::Initialize);
if (!FParse::Value(*ConfigEntry, TEXT("Bucket="), BucketName))
{
UE_LOG(LogVirtualization, Fatal, TEXT("[%s] 'Bucket=' not found in the config file"), *GetDebugString());
}
bool bAllowLocal = true;
if (FParse::Bool(*ConfigEntry, TEXT("LocalStorage="), bAllowLocal))
{
UE_LOG(LogVirtualization, Log, TEXT("[%s] Use of local storage set to '%s"), *GetDebugString(), bAllowLocal ? TEXT("true") : TEXT("false"));
}
bool bAllowRemote = true;
if (FParse::Bool(*ConfigEntry, TEXT("RemoteStorage="), bAllowRemote))
{
UE_LOG(LogVirtualization, Log, TEXT("[%s] Use of remote storage set to '%s"), *GetDebugString(), bAllowRemote ? TEXT("true") : TEXT("false"));
}
if (!bAllowLocal && !bAllowRemote)
{
UE_LOG(LogVirtualization, Fatal, TEXT("[%s] LocalStorage and RemoteStorage cannot both be disabled"), *GetDebugString());
return false;
}
if (bAllowLocal)
{
TransferPolicy |= UE::DerivedData::ECachePolicy::Local;
QueryPolicy |= UE::DerivedData::ECachePolicy::QueryLocal;
}
if (bAllowRemote)
{
TransferPolicy |= UE::DerivedData::ECachePolicy::Remote;
QueryPolicy |= UE::DerivedData::ECachePolicy::QueryRemote;
}
return true;
}
EPushResult FDDCBackend::PushData(const FPayloadId& Id, const FCompressedBuffer& Payload)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FDDCBackend::PushData);
if (DoesExist(Id))
{
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Already has a copy of the payload '%s'."), *GetDebugString(), *Id.ToString());
return EPushResult::PayloadAlreadyExisted;
}
UE::DerivedData::ICache& Cache = UE::DerivedData::GetCache();
UE::DerivedData::FCacheKey Key;
Key.Bucket = UE::DerivedData::FCacheBucket(BucketName);
Key.Hash = Id.GetIdentifier();
UE::DerivedData::FPayload DDCPayload = ToDDCPayload(Id, Payload);
check(DDCPayload.GetRawHash() == Id.GetIdentifier());
UE::DerivedData::FCacheRecordBuilder RecordBuilder(Key);
RecordBuilder.SetValue(DDCPayload);
UE::DerivedData::FRequestOwner Owner(UE::DerivedData::EPriority::Blocking);
UE::DerivedData::FCachePutCompleteParams Result;
auto Callback = [&Result](UE::DerivedData::FCachePutCompleteParams&& Params)
{
Result = Params;
};
Cache.Put( {RecordBuilder.Build()},
TEXT("Mirage"), // TODO: Improve this when we start passing more context to push
TransferPolicy,
Owner,
MoveTemp(Callback));
Owner.Wait();
if (Result.Status == UE::DerivedData::EStatus::Ok)
{
return EPushResult::Success;
}
else
{
return EPushResult::Failed;
}
}
FCompressedBuffer FDDCBackend::PullData(const FPayloadId& Id)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FDDCBackend::PullData);
UE::DerivedData::ICache& Cache = UE::DerivedData::GetCache();
UE::DerivedData::FCacheKey Key;
Key.Bucket = UE::DerivedData::FCacheBucket(BucketName);
Key.Hash = Id.GetIdentifier();
UE::DerivedData::FRequestOwner Owner(UE::DerivedData::EPriority::Blocking);
FCompressedBuffer ResultData;
UE::DerivedData::EStatus ResultStatus;
auto Callback = [&ResultData, &ResultStatus](UE::DerivedData::FCacheGetCompleteParams&& Params)
{
ResultStatus = Params.Status;
if (ResultStatus == UE::DerivedData::EStatus::Ok)
{
ResultData = Params.Record.GetValuePayload().GetData();
}
};
Cache.Get( {Key},
TEXT("Mirage"), // TODO: Improve this when we start passing more context to push
TransferPolicy,
Owner,
MoveTemp(Callback));
Owner.Wait();
return ResultData;
}
FString FDDCBackend::GetDebugString() const
{
return DebugName;
}
bool FDDCBackend::DoesExist(const FPayloadId& Id) const
{
TRACE_CPUPROFILER_EVENT_SCOPE(FDDCBackend::DoesExist);
UE::DerivedData::ICache& Cache = UE::DerivedData::GetCache();
UE::DerivedData::FCacheKey Key;
Key.Bucket = UE::DerivedData::FCacheBucket(BucketName);
Key.Hash = Id.GetIdentifier();
UE::DerivedData::FRequestOwner Owner(UE::DerivedData::EPriority::Blocking);
UE::DerivedData::EStatus ResultStatus;
auto Callback = [&ResultStatus](UE::DerivedData::FCacheGetCompleteParams&& Params)
{
ResultStatus = Params.Status;
};
Cache.Get( { Key },
TEXT("Mirage"), // TODO: Improve this when we start passing more context to push
QueryPolicy | UE::DerivedData::ECachePolicy::SkipData,
Owner,
MoveTemp(Callback));
Owner.Wait();
return ResultStatus == UE::DerivedData::EStatus::Ok;
}
UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY(FDDCBackend, DDCBackend);
} // namespace UE::Virtualization