You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
The cache stores can individually control their "legacy mode" now, which offers a choice of ValueOnly, ValueWithLegacyFallback, LegacyOnly. - Using ValueOnly will forward every legacy request through the Value API, which compresses values by default and supports values larger than 2 GiB. - Using ValueWithLegacyFallback behaves like ValueOnly, but misses from GetValue are forwarded to GetCachedData, and stored with PutValue if found. - Using LegacyOnly will forward every legacy request through the Legacy API. FLegacyCacheValue uses shared state to ensure that each value is compressed or decompressed at most once. #jira UE-134381 #preflight 62054b430c64e1822f41231b #lockdown Mark.Lintott #rb Zousar.Shaker #rnx #ROBOMERGE-AUTHOR: devin.doucette #ROBOMERGE-SOURCE: CL 18940270 in //UE5/Release-5.0/... via CL 18941016 via CL 18941392 #ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v917-18934589) [CL 18941401 by devin doucette in ue5-main branch]
227 lines
6.7 KiB
C++
227 lines
6.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DerivedDataLegacyCacheStore.h"
|
|
|
|
#include "Containers/StringConv.h"
|
|
#include "DerivedDataBackendInterface.h"
|
|
#include "Misc/Crc.h"
|
|
#include "Misc/ScopeRWLock.h"
|
|
#include "Misc/SecureHash.h"
|
|
#include "Misc/StringBuilder.h"
|
|
#include "String/BytesToHex.h"
|
|
#include "String/Find.h"
|
|
|
|
namespace UE::DerivedData
|
|
{
|
|
|
|
void ILegacyCacheStore::LegacyPut(
|
|
const TConstArrayView<FLegacyCachePutRequest> Requests,
|
|
IRequestOwner& Owner,
|
|
FOnLegacyCachePutComplete&& OnComplete)
|
|
{
|
|
struct FKeyWithUserData
|
|
{
|
|
FLegacyCacheKey Key;
|
|
uint64 UserData;
|
|
};
|
|
|
|
TArray<FKeyWithUserData, TInlineAllocator<1>> LegacyRequests;
|
|
TArray<FCachePutValueRequest, TInlineAllocator<1>> ValueRequests;
|
|
LegacyRequests.Reserve(Requests.Num());
|
|
ValueRequests.Reserve(Requests.Num());
|
|
|
|
uint64 RequestIndex = 0;
|
|
for (const FLegacyCachePutRequest& Request : Requests)
|
|
{
|
|
LegacyRequests.Add({Request.Key, Request.UserData});
|
|
ValueRequests.Add({Request.Name, Request.Key.GetKey(), Request.Value.GetValue(), Request.Policy, RequestIndex++});
|
|
}
|
|
|
|
PutValue(ValueRequests, Owner, [LegacyRequests = MoveTemp(LegacyRequests), OnComplete = MoveTemp(OnComplete)](FCachePutValueResponse&& Response)
|
|
{
|
|
const FKeyWithUserData& LegacyRequest = LegacyRequests[int32(Response.UserData)];
|
|
OnComplete({Response.Name, LegacyRequest.Key, LegacyRequest.UserData, Response.Status});
|
|
});
|
|
}
|
|
|
|
void ILegacyCacheStore::LegacyGet(
|
|
const TConstArrayView<FLegacyCacheGetRequest> Requests,
|
|
IRequestOwner& Owner,
|
|
FOnLegacyCacheGetComplete&& OnComplete)
|
|
{
|
|
struct FKeyWithUserData
|
|
{
|
|
FLegacyCacheKey Key;
|
|
uint64 UserData;
|
|
};
|
|
|
|
TArray<FKeyWithUserData, TInlineAllocator<1>> LegacyRequests;
|
|
TArray<FCacheGetValueRequest, TInlineAllocator<1>> ValueRequests;
|
|
LegacyRequests.Reserve(Requests.Num());
|
|
ValueRequests.Reserve(Requests.Num());
|
|
|
|
uint64 RequestIndex = 0;
|
|
for (const FLegacyCacheGetRequest& Request : Requests)
|
|
{
|
|
LegacyRequests.Add({Request.Key, Request.UserData});
|
|
ValueRequests.Add({Request.Name, Request.Key.GetKey(), Request.Policy, RequestIndex++});
|
|
}
|
|
|
|
GetValue(ValueRequests, Owner, [LegacyRequests = MoveTemp(LegacyRequests), OnComplete = MoveTemp(OnComplete)](FCacheGetValueResponse&& Response)
|
|
{
|
|
const FKeyWithUserData& LegacyRequest = LegacyRequests[int32(Response.UserData)];
|
|
OnComplete({Response.Name, LegacyRequest.Key, FLegacyCacheValue(Response.Value), LegacyRequest.UserData, Response.Status});
|
|
});
|
|
}
|
|
|
|
void ILegacyCacheStore::LegacyDelete(
|
|
const TConstArrayView<FLegacyCacheDeleteRequest> Requests,
|
|
IRequestOwner& Owner,
|
|
FOnLegacyCacheDeleteComplete&& OnComplete)
|
|
{
|
|
CompleteWithStatus(Requests, OnComplete, EStatus::Error);
|
|
}
|
|
|
|
FLegacyCacheKey::FLegacyCacheKey(const FStringView InFullKey, const int32 MaxKeyLength)
|
|
: FullKey(InFullKey)
|
|
{
|
|
if (InFullKey.Len() > MaxKeyLength)
|
|
{
|
|
const auto FullKeyUCS2 = StringCast<UCS2CHAR>(InFullKey.GetData(), InFullKey.Len());
|
|
const int32 FullKeyLength = FullKeyUCS2.Length();
|
|
const uint32 CRCofPayload(FCrc::MemCrc32(FullKeyUCS2.Get(), FullKeyLength * sizeof(UCS2CHAR)));
|
|
|
|
uint8 Hash[FSHA1::DigestSize];
|
|
FSHA1 HashState;
|
|
HashState.Update((const uint8*)&FullKeyLength, sizeof(int32));
|
|
HashState.Update((const uint8*)&CRCofPayload, sizeof(uint32));
|
|
HashState.Update((const uint8*)FullKeyUCS2.Get(), FullKeyLength * sizeof(UCS2CHAR));
|
|
HashState.Final();
|
|
HashState.GetHash(Hash);
|
|
|
|
TStringBuilder<128> ShortKeyBuilder;
|
|
ShortKeyBuilder << InFullKey.Left(MaxKeyLength - FSHA1::DigestSize * 2 - 2) << TEXT("__");
|
|
String::BytesToHex(Hash, ShortKeyBuilder);
|
|
|
|
check(ShortKeyBuilder.Len() == MaxKeyLength && ShortKeyBuilder.Len() > 0);
|
|
ShortKey = ShortKeyBuilder;
|
|
}
|
|
|
|
TStringBuilder<64> Bucket;
|
|
Bucket << TEXT("Legacy");
|
|
if (const int32 BucketEnd = String::FindFirstChar(InFullKey, TEXT('_')); BucketEnd != INDEX_NONE)
|
|
{
|
|
Bucket << InFullKey.Left(BucketEnd);
|
|
}
|
|
Key.Bucket = FCacheBucket(Bucket);
|
|
Key.Hash = FIoHash::HashBuffer(MakeMemoryView(FTCHARToUTF8(InFullKey)));
|
|
}
|
|
|
|
bool FLegacyCacheKey::ReadValueTrailer(FCompositeBuffer& Value) const
|
|
{
|
|
if (!ShortKey.IsEmpty())
|
|
{
|
|
TUtf8StringBuilder<256> FullKeyUtf8;
|
|
FullKeyUtf8 << FullKey;
|
|
const FMemoryView CompareKey(FullKeyUtf8.ToString(), (FullKeyUtf8.Len() + 1) * sizeof(UTF8CHAR));
|
|
if (Value.GetSize() < CompareKey.GetSize())
|
|
{
|
|
UE_LOG(LogDerivedDataCache, Display, TEXT("FLegacyCacheKey: Hash collision or short value for key %s."), *FullKey);
|
|
return false;
|
|
}
|
|
FUniqueBuffer CopyBuffer;
|
|
const uint64 KeyOffset = Value.GetSize() - CompareKey.GetSize();
|
|
const FMemoryView ValueKey = Value.ViewOrCopyRange(KeyOffset, CompareKey.GetSize(), CopyBuffer);
|
|
if (!CompareKey.EqualBytes(ValueKey))
|
|
{
|
|
UE_LOG(LogDerivedDataCache, Display, TEXT("FLegacyCacheKey: Hash collision for key %s."), *FullKey);
|
|
return false;
|
|
}
|
|
Value = Value.Mid(0, KeyOffset);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FLegacyCacheKey::WriteValueTrailer(FCompositeBuffer& Value) const
|
|
{
|
|
if (!ShortKey.IsEmpty())
|
|
{
|
|
TUtf8StringBuilder<256> FullKeyUtf8;
|
|
FullKeyUtf8 << FullKey;
|
|
Value = FCompositeBuffer(Value, FSharedBuffer::Clone(FullKeyUtf8.ToString(), (FullKeyUtf8.Len() + 1) * sizeof(UTF8CHAR)));
|
|
}
|
|
}
|
|
|
|
FLegacyCacheValue::FLegacyCacheValue(const FValue& Value)
|
|
{
|
|
if (Value.HasData() || !Value.GetRawHash().IsZero())
|
|
{
|
|
Shared = new Private::FLegacyCacheValueShared(Value);
|
|
}
|
|
}
|
|
|
|
FLegacyCacheValue::FLegacyCacheValue(const FCompositeBuffer& RawData)
|
|
{
|
|
if (RawData)
|
|
{
|
|
Shared = new Private::FLegacyCacheValueShared(RawData);
|
|
}
|
|
}
|
|
|
|
Private::FLegacyCacheValueShared::FLegacyCacheValueShared(const FValue& InValue)
|
|
: Value(InValue)
|
|
{
|
|
}
|
|
|
|
Private::FLegacyCacheValueShared::FLegacyCacheValueShared(const FCompositeBuffer& InRawData)
|
|
: RawData(InRawData.MakeOwned())
|
|
{
|
|
}
|
|
|
|
const FValue& Private::FLegacyCacheValueShared::GetValue()
|
|
{
|
|
FWriteScopeLock WriteLock(Lock);
|
|
if (!Value.HasData() && !RawData.IsNull())
|
|
{
|
|
Value = FValue::Compress(RawData);
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
const FCompositeBuffer& Private::FLegacyCacheValueShared::GetRawData()
|
|
{
|
|
FWriteScopeLock WriteLock(Lock);
|
|
if (RawData.IsNull() && Value.HasData())
|
|
{
|
|
RawData = Value.GetData().DecompressToComposite();
|
|
}
|
|
return RawData;
|
|
}
|
|
|
|
FIoHash Private::FLegacyCacheValueShared::GetRawHash() const
|
|
{
|
|
return Value.HasData() ? Value.GetRawHash() : FIoHash::HashBuffer(RawData);
|
|
}
|
|
|
|
uint64 Private::FLegacyCacheValueShared::GetRawSize() const
|
|
{
|
|
return Value.HasData() ? Value.GetRawSize() : RawData.GetSize();
|
|
}
|
|
|
|
FLegacyCachePutResponse FLegacyCachePutRequest::MakeResponse(const EStatus Status) const
|
|
{
|
|
return {Name, Key, UserData, Status};
|
|
}
|
|
|
|
FLegacyCacheGetResponse FLegacyCacheGetRequest::MakeResponse(const EStatus Status) const
|
|
{
|
|
return {Name, Key, {}, UserData, Status};
|
|
}
|
|
|
|
FLegacyCacheDeleteResponse FLegacyCacheDeleteRequest::MakeResponse(const EStatus Status) const
|
|
{
|
|
return {Name, Key, UserData, Status};
|
|
}
|
|
|
|
} // UE::DerivedData
|