2022-05-30 18:14:02 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2022-05-31 23:25:37 -04:00
# include "DerivedDataLegacyCacheStore.h"
2022-12-09 16:11:41 -05:00
# include "Experimental/ZenServerInterface.h"
2024-01-09 06:08:29 -05:00
# include "Experimental/ZenStatistics.h"
2022-05-30 18:14:02 -04:00
# if UE_WITH_ZEN
2023-11-07 17:56:15 -05:00
# include "Async/ManualResetEvent.h"
2023-06-13 17:14:59 -04:00
# include "Async/UniqueLock.h"
2022-05-30 18:14:02 -04:00
# include "BatchView.h"
2022-05-31 22:01:53 -04:00
# include "DerivedDataBackendInterface.h"
2022-05-30 18:14:02 -04:00
# include "DerivedDataCachePrivate.h"
# include "DerivedDataCacheRecord.h"
# include "DerivedDataCacheUsageStats.h"
# include "DerivedDataChunk.h"
2022-07-18 12:23:16 -04:00
# include "DerivedDataRequest.h"
2022-06-10 12:56:08 -04:00
# include "DerivedDataRequestOwner.h"
2022-12-09 16:11:41 -05:00
# include "Experimental/ZenStatistics.h"
2023-01-03 15:58:30 -05:00
# include "HAL/FileManager.h"
2023-11-07 17:56:15 -05:00
# include "HAL/Thread.h"
2022-05-31 12:42:17 -04:00
# include "Http/HttpClient.h"
2022-06-20 02:08:49 -04:00
# include "Math/UnrealMathUtility.h"
2022-05-31 22:01:53 -04:00
# include "Misc/App.h"
2022-05-30 18:14:02 -04:00
# include "Misc/ConfigCacheIni.h"
# include "Misc/Optional.h"
# include "ProfilingDebugging/CountersTrace.h"
# include "ProfilingDebugging/CpuProfilerTrace.h"
# include "Serialization/CompactBinary.h"
# include "Serialization/CompactBinaryPackage.h"
# include "Serialization/CompactBinaryWriter.h"
2022-05-31 12:42:17 -04:00
# include "Serialization/LargeMemoryWriter.h"
2022-07-18 12:23:16 -04:00
# include "Serialization/MemoryReader.h"
2022-05-31 12:42:17 -04:00
# include "Templates/Function.h"
2022-05-30 18:14:02 -04:00
# include "ZenBackendUtils.h"
# include "ZenSerialization.h"
2024-02-07 09:25:38 -05:00
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_Get , TEXT ( " ZenDDC Get " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_GetHit , TEXT ( " ZenDDC Get Hit " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_Put , TEXT ( " ZenDDC Put " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_PutHit , TEXT ( " ZenDDC Put Hit " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_BytesReceived , TEXT ( " ZenDDC Bytes Received " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_BytesSent , TEXT ( " ZenDDC Bytes Sent " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_CacheRecordRequestCountInFlight , TEXT ( " ZenDDC CacheRecord Request Count " ) ) ;
TRACE_DECLARE_ATOMIC_INT_COUNTER ( ZenDDC_ChunkRequestCountInFlight , TEXT ( " ZenDDC Chunk Request Count " ) ) ;
2022-05-30 18:14:02 -04:00
namespace UE : : DerivedData
{
template < typename T >
void ForEachBatch ( const int32 BatchSize , const int32 TotalCount , T & & Fn )
{
check ( BatchSize > 0 ) ;
if ( TotalCount > 0 )
{
const int32 BatchCount = FMath : : DivideAndRoundUp ( TotalCount , BatchSize ) ;
const int32 Last = TotalCount - 1 ;
for ( int32 BatchIndex = 0 ; BatchIndex < BatchCount ; BatchIndex + + )
{
const int32 BatchFirstIndex = BatchIndex * BatchSize ;
const int32 BatchLastIndex = FMath : : Min ( BatchFirstIndex + BatchSize - 1 , Last ) ;
Fn ( BatchFirstIndex , BatchLastIndex ) ;
}
}
}
2023-11-25 16:22:26 -05:00
struct FZenCacheStoreParams
{
FString Name ;
FString Host ;
FString Namespace ;
FString Sandbox ;
int32 MaxBatchPutKB = 1024 ;
int32 RecordBatchSize = 8 ;
int32 ChunksBatchSize = 8 ;
float DeactivateAtMs = - 1.0f ;
TOptional < bool > bLocal ;
TOptional < bool > bRemote ;
bool bFlush = false ;
bool bReadOnly = false ;
void Parse ( const TCHAR * NodeName , const TCHAR * Config ) ;
} ;
2022-05-30 18:14:02 -04:00
/**
* Backend for a HTTP based caching service ( Zen )
*/
2022-05-31 22:01:53 -04:00
class FZenCacheStore final : public ILegacyCacheStore
2022-05-30 18:14:02 -04:00
{
public :
/**
2022-05-31 22:01:53 -04:00
* Creates the cache store client , checks health status and attempts to acquire an access token .
2022-05-30 18:14:02 -04:00
*
2022-07-18 12:23:16 -04:00
* @ param ServiceUrl Base url to the service including scheme .
2022-05-30 18:14:02 -04:00
* @ param Namespace Namespace to use .
*/
2023-06-13 17:14:59 -04:00
FZenCacheStore (
2023-11-25 16:22:26 -05:00
const FZenCacheStoreParams & InParams ,
2023-06-13 17:14:59 -04:00
ICacheStoreOwner * Owner ) ;
2022-05-30 18:14:02 -04:00
2023-06-13 17:14:59 -04:00
FZenCacheStore (
UE : : Zen : : FServiceSettings & & Settings ,
2023-11-25 16:22:26 -05:00
const FZenCacheStoreParams & InParams ,
2023-06-13 17:14:59 -04:00
ICacheStoreOwner * Owner ) ;
2023-01-03 15:58:30 -05:00
2023-06-14 10:12:47 -04:00
~ FZenCacheStore ( ) final ;
2024-01-18 22:43:41 -05:00
inline const FString & GetName ( ) const { return NodeName ; }
2022-05-30 18:14:02 -04:00
/**
2022-05-31 22:01:53 -04:00
* Checks if cache service is usable ( reachable and accessible ) .
2022-05-30 18:14:02 -04:00
* @ return true if usable
*/
2022-05-31 22:01:53 -04:00
inline bool IsUsable ( ) const { return bIsUsable ; }
2022-05-30 18:14:02 -04:00
2023-11-15 17:17:29 -05:00
/**
* Checks if cache service is on the local machine .
* @ return true if it is local
*/
inline bool IsLocalConnection ( ) const { return bIsLocalConnection ; }
2022-05-30 18:14:02 -04:00
// ICacheStore
2022-05-31 22:01:53 -04:00
void Put (
2022-05-30 18:14:02 -04:00
TConstArrayView < FCachePutRequest > Requests ,
IRequestOwner & Owner ,
2022-05-31 22:01:53 -04:00
FOnCachePutComplete & & OnComplete = FOnCachePutComplete ( ) ) final ;
2022-05-30 18:14:02 -04:00
2022-05-31 22:01:53 -04:00
void Get (
2022-05-30 18:14:02 -04:00
TConstArrayView < FCacheGetRequest > Requests ,
IRequestOwner & Owner ,
2022-05-31 22:01:53 -04:00
FOnCacheGetComplete & & OnComplete ) final ;
2022-05-30 18:14:02 -04:00
2022-05-31 22:01:53 -04:00
void PutValue (
2022-05-30 18:14:02 -04:00
TConstArrayView < FCachePutValueRequest > Requests ,
IRequestOwner & Owner ,
2022-05-31 22:01:53 -04:00
FOnCachePutValueComplete & & OnComplete = FOnCachePutValueComplete ( ) ) final ;
2022-05-30 18:14:02 -04:00
2022-05-31 22:01:53 -04:00
void GetValue (
2022-05-30 18:14:02 -04:00
TConstArrayView < FCacheGetValueRequest > Requests ,
IRequestOwner & Owner ,
2022-05-31 22:01:53 -04:00
FOnCacheGetValueComplete & & OnComplete = FOnCacheGetValueComplete ( ) ) final ;
2022-05-30 18:14:02 -04:00
2022-05-31 22:01:53 -04:00
void GetChunks (
2022-05-30 18:14:02 -04:00
TConstArrayView < FCacheGetChunkRequest > Requests ,
IRequestOwner & Owner ,
2022-05-31 22:01:53 -04:00
FOnCacheGetChunkComplete & & OnComplete ) final ;
// ILegacyCacheStore
void LegacyStats ( FDerivedDataCacheStatsNode & OutNode ) final ;
bool LegacyDebugOptions ( FBackendDebugOptions & Options ) final ;
2022-05-30 18:14:02 -04:00
2023-03-28 13:43:50 -04:00
const Zen : : FZenServiceInstance & GetServiceInstance ( ) const { return ZenService . GetInstance ( ) ; }
2022-05-30 18:14:02 -04:00
private :
2023-11-25 16:22:26 -05:00
void Initialize ( const FZenCacheStoreParams & Params ) ;
2023-01-03 15:58:30 -05:00
2022-05-30 18:14:02 -04:00
bool IsServiceReady ( ) ;
2022-07-18 12:23:16 -04:00
static FCompositeBuffer SaveRpcPackage ( const FCbPackage & Package ) ;
THttpUniquePtr < IHttpRequest > CreateRpcRequest ( ) ;
using FOnRpcComplete = TUniqueFunction < void ( THttpUniquePtr < IHttpResponse > & HttpResponse , FCbPackage & Response ) > ;
void EnqueueAsyncRpc ( IRequestOwner & Owner , FCbObject RequestObject , FOnRpcComplete & & OnComplete ) ;
void EnqueueAsyncRpc ( IRequestOwner & Owner , const FCbPackage & RequestPackage , FOnRpcComplete & & OnComplete ) ;
2022-06-10 12:56:08 -04:00
2023-12-13 11:34:21 -05:00
void ActivatePerformanceEvaluationThread ( ) ;
2023-11-07 17:56:15 -05:00
void ConditionalEvaluatePerformance ( ) ;
2024-01-09 06:08:29 -05:00
void ConditionalUpdateStorageSize ( ) ;
2023-11-07 17:56:15 -05:00
void UpdateStatus ( ) ;
2022-06-10 12:56:08 -04:00
template < typename T , typename . . . ArgTypes >
static TRefCountPtr < T > MakeAsyncOp ( ArgTypes & & . . . Args )
{
// TODO: This should in-place construct from a pre-allocated memory pool
return TRefCountPtr < T > ( new T ( Forward < ArgTypes > ( Args ) . . . ) ) ;
}
2022-07-18 12:23:16 -04:00
2022-05-30 18:14:02 -04:00
private :
2023-06-13 17:14:59 -04:00
template < typename RequestType >
struct TRequestWithStats ;
template < typename OutContainerType , typename InContainerType , typename BucketAccessorType , typename RequestTypeAccessorType >
static void StartRequests (
OutContainerType & Out ,
const InContainerType & In ,
BucketAccessorType BucketAccessor ,
RequestTypeAccessorType TypeAccessor ,
const ERequestOp Op ) ;
2022-07-18 12:23:16 -04:00
class FPutOp ;
class FGetOp ;
class FPutValueOp ;
class FGetValueOp ;
class FGetChunksOp ;
2023-12-13 11:34:21 -05:00
enum class EHealth
2023-11-07 17:56:15 -05:00
{
Unknown ,
Ok ,
Error ,
} ;
2023-12-13 11:34:21 -05:00
using FOnHealthComplete = TUniqueFunction < void ( THttpUniquePtr < IHttpResponse > & HttpResponse , EHealth Health ) > ;
class FHealthReceiver ;
class FAsyncHealthReceiver ;
2023-11-07 17:56:15 -05:00
2022-07-18 12:23:16 -04:00
class FCbPackageReceiver ;
class FAsyncCbPackageReceiver ;
2022-06-10 12:56:08 -04:00
2024-01-18 22:43:41 -05:00
FString NodeName ;
2022-05-30 18:14:02 -04:00
FString Namespace ;
UE : : Zen : : FScopeZenService ZenService ;
2023-06-13 17:14:59 -04:00
ICacheStoreOwner * StoreOwner = nullptr ;
ICacheStoreStats * StoreStats = nullptr ;
2022-07-18 12:23:16 -04:00
THttpUniquePtr < IHttpConnectionPool > ConnectionPool ;
FHttpRequestQueue RequestQueue ;
2022-05-30 18:14:02 -04:00
bool bIsUsable = false ;
2022-11-07 05:33:21 -05:00
bool bIsLocalConnection = false ;
2023-11-07 17:56:15 -05:00
bool bTryEvaluatePerformance = false ;
std : : atomic < bool > bDeactivatedForPerformance = false ;
2023-11-25 16:22:26 -05:00
int32 MaxBatchPutKB = 1024 ;
2022-05-30 18:14:02 -04:00
int32 CacheRecordBatchSize = 8 ;
int32 CacheChunksBatchSize = 8 ;
FBackendDebugOptions DebugOptions ;
2022-07-18 12:23:16 -04:00
TAnsiStringBuilder < 256 > RpcUri ;
2023-11-07 17:56:15 -05:00
std : : atomic < int64 > LastPerformanceEvaluationTicks ;
TOptional < FThread > PerformanceEvaluationThread ;
FManualResetEvent PerformanceEvaluationThreadShutdownEvent ;
2024-01-09 06:08:29 -05:00
std : : atomic < int64 > LastStorageSizeUpdateTicks ;
2023-11-07 17:56:15 -05:00
float DeactivateAtMs = - 1.0f ;
ECacheStoreFlags OperationalFlags ;
FRequestOwner PerformanceEvaluationRequestOwner ;
2022-05-30 18:14:02 -04:00
} ;
2023-06-13 17:14:59 -04:00
template < typename RequestType >
struct FZenCacheStore : : TRequestWithStats
{
RequestType Request ;
mutable FRequestStats Stats ;
explicit TRequestWithStats ( const RequestType & InRequest )
: Request ( InRequest )
{
}
void EndRequest ( FZenCacheStore & Outer , const EStatus Status ) const
{
{
TUniqueLock Lock ( Stats . Mutex ) ;
Stats . EndTime = FMonotonicTimePoint : : Now ( ) ;
Stats . Status = Status ;
}
if ( Outer . StoreStats )
{
Outer . StoreStats - > AddRequest ( Stats ) ;
}
}
} ;
template < typename OutContainerType , typename InContainerType , typename BucketAccessorType , typename RequestTypeAccessorType >
void FZenCacheStore : : StartRequests (
OutContainerType & Out ,
const InContainerType & In ,
BucketAccessorType BucketAccessor ,
RequestTypeAccessorType TypeAccessor ,
const ERequestOp Op )
{
const FMonotonicTimePoint Now = FMonotonicTimePoint : : Now ( ) ;
Out . Reserve ( In . Num ( ) ) ;
for ( const auto & Request : In )
{
auto & RequestWithStats = Out [ Out . Emplace ( Request ) ] ;
2023-06-23 10:51:52 -04:00
RequestWithStats . Stats . Name = Request . Name ;
2023-06-13 17:14:59 -04:00
RequestWithStats . Stats . Bucket = BucketAccessor ( Request ) ;
RequestWithStats . Stats . Type = TypeAccessor ( Request ) ;
RequestWithStats . Stats . Op = Op ;
RequestWithStats . Stats . StartTime = Now ;
}
}
2022-07-18 12:23:16 -04:00
class FZenCacheStore : : FPutOp final : public FThreadSafeRefCountedObject
2022-06-10 12:56:08 -04:00
{
public :
FPutOp ( FZenCacheStore & InCacheStore ,
IRequestOwner & InOwner ,
const TConstArrayView < FCachePutRequest > InRequests ,
FOnCachePutComplete & & InOnComplete )
: CacheStore ( InCacheStore )
, Owner ( InOwner )
, OnComplete ( MoveTemp ( InOnComplete ) )
{
2023-06-13 17:14:59 -04:00
StartRequests ( Requests , InRequests , [ ] ( const FCachePutRequest & Request ) { return Request . Record . GetKey ( ) . Bucket ; } ,
[ ] ( auto & ) { return ERequestType : : Record ; } , ERequestOp : : Put ) ;
Batches = TBatchView < const TRequestWithStats < FCachePutRequest > > ( Requests ,
[ this ] ( const TRequestWithStats < FCachePutRequest > & NextRequest ) { return BatchGroupingFilter ( NextRequest . Request ) ; } ) ;
TRACE_COUNTER_ADD ( ZenDDC_Put , int64 ( Requests . Num ( ) ) ) ;
2022-06-10 12:56:08 -04:00
}
2023-09-20 02:58:55 -04:00
virtual ~ FPutOp ( )
{
FMonotonicTimeSpan AverageMainThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . MainThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageOtherThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . OtherThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageLatency = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . Latency . ToSeconds ( ) / Requests . Num ( ) ) ;
for ( TRequestWithStats < FCachePutRequest > & Request : Requests )
{
Request . Stats . MainThreadTime = AverageMainThreadTime ;
Request . Stats . OtherThreadTime = AverageOtherThreadTime ;
Request . Stats . Latency = AverageLatency ;
}
2023-11-07 17:56:15 -05:00
CacheStore . ConditionalEvaluatePerformance ( ) ;
2024-01-09 06:08:29 -05:00
CacheStore . ConditionalUpdateStorageSize ( ) ;
2023-09-20 02:58:55 -04:00
}
2022-06-10 12:56:08 -04:00
void IssueRequests ( )
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2022-06-10 12:56:08 -04:00
FRequestBarrier Barrier ( Owner ) ;
2023-06-13 17:14:59 -04:00
for ( TArrayView < const TRequestWithStats < FCachePutRequest > > Batch : Batches )
2022-06-10 12:56:08 -04:00
{
FCbPackage BatchPackage ;
FCbWriter BatchWriter ;
BatchWriter . BeginObject ( ) ;
{
BatchWriter < < ANSITEXTVIEW ( " Method " ) < < " PutCacheRecords " ;
2022-10-13 11:17:53 -04:00
BatchWriter . AddInteger ( ANSITEXTVIEW ( " Accept " ) , Zen : : Http : : kCbPkgMagic ) ;
2022-06-10 12:56:08 -04:00
BatchWriter . BeginObject ( ANSITEXTVIEW ( " Params " ) ) ;
{
2023-06-13 17:14:59 -04:00
ECachePolicy BatchDefaultPolicy = Batch [ 0 ] . Request . Policy . GetRecordPolicy ( ) ;
2022-06-10 12:56:08 -04:00
BatchWriter < < ANSITEXTVIEW ( " DefaultPolicy " ) < < * WriteToString < 128 > ( BatchDefaultPolicy ) ;
2022-07-18 12:23:16 -04:00
BatchWriter . AddString ( ANSITEXTVIEW ( " Namespace " ) , CacheStore . Namespace ) ;
2022-06-10 12:56:08 -04:00
BatchWriter . BeginArray ( ANSITEXTVIEW ( " Requests " ) ) ;
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCachePutRequest > & RequestWithStats : Batch )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
const FCachePutRequest & Request = RequestWithStats . Request ;
2022-06-10 12:56:08 -04:00
const FCacheRecord & Record = Request . Record ;
BatchWriter . BeginObject ( ) ;
{
BatchWriter . SetName ( ANSITEXTVIEW ( " Record " ) ) ;
Record . Save ( BatchPackage , BatchWriter ) ;
2023-06-14 12:31:13 -04:00
if ( ( ! Request . Policy . IsUniform ( ) ) | | ( Request . Policy . GetRecordPolicy ( ) ! = BatchDefaultPolicy ) )
2022-06-10 12:56:08 -04:00
{
2022-06-20 23:40:25 -04:00
BatchWriter < < ANSITEXTVIEW ( " Policy " ) < < Request . Policy ;
2022-06-10 12:56:08 -04:00
}
}
BatchWriter . EndObject ( ) ;
}
BatchWriter . EndArray ( ) ;
}
BatchWriter . EndObject ( ) ;
}
BatchWriter . EndObject ( ) ;
BatchPackage . SetObject ( BatchWriter . Save ( ) . AsObject ( ) ) ;
2022-07-18 12:23:16 -04:00
auto OnRpcComplete = [ this , OpRef = TRefCountPtr < FPutOp > ( this ) , Batch ] ( THttpUniquePtr < IHttpResponse > & HttpResponse , FCbPackage & Response )
2022-06-10 12:56:08 -04:00
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2023-11-07 17:56:15 -05:00
// Latency can't be measured for Put operations because it is intertwined with upload time.
Requests [ 0 ] . Stats . Latency = FMonotonicTimeSpan : : Infinity ( ) ;
2023-09-20 02:58:55 -04:00
2022-06-10 12:56:08 -04:00
int32 RequestIndex = 0 ;
2023-05-09 08:08:07 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : None & & HttpResponse - > GetStatusCode ( ) > = 200 & & HttpResponse - > GetStatusCode ( ) < = 299 )
2022-06-10 12:56:08 -04:00
{
const FCbObject & ResponseObj = Response . GetObject ( ) ;
for ( FCbField ResponseField : ResponseObj [ ANSITEXTVIEW ( " Result " ) ] )
{
if ( RequestIndex > = Batch . Num ( ) )
{
+ + RequestIndex ;
continue ;
}
2023-06-13 17:14:59 -04:00
const TRequestWithStats < FCachePutRequest > & RequestWithStats = Batch [ RequestIndex + + ] ;
const FCacheKey & Key = RequestWithStats . Request . Record . GetKey ( ) ;
2022-06-10 12:56:08 -04:00
bool bPutSucceeded = ResponseField . AsBool ( ) ;
if ( CacheStore . DebugOptions . ShouldSimulatePutMiss ( Key ) )
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Simulated miss for put of %s from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( Key ) , * RequestWithStats . Request . Name ) ;
2022-06-10 12:56:08 -04:00
bPutSucceeded = false ;
}
2023-06-13 17:14:59 -04:00
bPutSucceeded ? OnHit ( RequestWithStats ) : OnMiss ( RequestWithStats ) ;
2022-06-10 12:56:08 -04:00
}
if ( RequestIndex ! = Batch . Num ( ) )
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2022-07-21 23:01:51 -04:00
TEXT ( " %s: Invalid response received from PutCacheRecords RPC: %d results expected, received %d, from %s " ) ,
* CacheStore . GetName ( ) , Batch . Num ( ) , RequestIndex , * WriteToString < 256 > ( * HttpResponse ) ) ;
2022-06-10 12:56:08 -04:00
}
}
2023-09-18 15:22:34 -04:00
else if ( ( HttpResponse - > GetErrorCode ( ) ! = EHttpErrorCode : : Canceled ) & & ( HttpResponse - > GetStatusCode ( ) ! = 404 ) )
2023-05-09 08:08:07 -04:00
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-05-09 08:08:07 -04:00
TEXT ( " %s: Error response received from PutCacheRecords RPC: from %s " ) ,
* CacheStore . GetName ( ) , * WriteToString < 256 > ( * HttpResponse ) ) ;
}
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCachePutRequest > & RequestWithStats : Batch . RightChop ( RequestIndex ) )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : Canceled )
{
OnCanceled ( RequestWithStats ) ;
}
else
{
OnMiss ( RequestWithStats ) ;
}
2022-06-10 12:56:08 -04:00
}
} ;
2022-07-18 12:23:16 -04:00
CacheStore . EnqueueAsyncRpc ( Owner , BatchPackage , MoveTemp ( OnRpcComplete ) ) ;
2022-06-10 12:56:08 -04:00
}
}
private :
EBatchView BatchGroupingFilter ( const FCachePutRequest & NextRequest )
{
const FCacheRecord & Record = NextRequest . Record ;
uint64 RecordSize = sizeof ( FCacheKey ) + Record . GetMeta ( ) . GetSize ( ) ;
for ( const FValueWithId & Value : Record . GetValues ( ) )
{
RecordSize + = Value . GetData ( ) . GetCompressedSize ( ) ;
}
BatchSize + = RecordSize ;
2023-11-25 16:22:26 -05:00
if ( BatchSize > CacheStore . MaxBatchPutKB * 1024 )
2022-06-10 12:56:08 -04:00
{
BatchSize = RecordSize ;
return EBatchView : : NewBatch ;
}
return EBatchView : : Continue ;
}
2023-06-13 17:14:59 -04:00
void OnHit ( const TRequestWithStats < FCachePutRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache put complete for %s from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Record . GetKey ( ) ) , * RequestWithStats . Request . Name ) ;
if ( const FCbObject & Meta = RequestWithStats . Request . Record . GetMeta ( ) )
2023-02-14 03:09:44 -05:00
{
2023-06-13 17:14:59 -04:00
RequestWithStats . Stats . PhysicalWriteSize + = Meta . GetSize ( ) ;
2023-02-14 03:09:44 -05:00
}
2023-06-13 17:14:59 -04:00
for ( const FValueWithId & Value : RequestWithStats . Request . Record . GetValues ( ) )
{
RequestWithStats . Stats . AddLogicalWrite ( Value ) ;
RequestWithStats . Stats . PhysicalWriteSize + = Value . GetData ( ) . GetCompressedSize ( ) ;
}
RequestWithStats . EndRequest ( CacheStore , EStatus : : Ok ) ;
TRACE_COUNTER_ADD ( ZenDDC_BytesSent , int64 ( RequestWithStats . Stats . PhysicalWriteSize ) ) ;
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_INCREMENT ( ZenDDC_PutHit ) ;
2023-06-13 17:14:59 -04:00
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Ok ) ) ;
}
2023-02-14 03:09:44 -05:00
2023-06-13 17:14:59 -04:00
void OnMiss ( const TRequestWithStats < FCachePutRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache put failed for '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Record . GetKey ( ) ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Error ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Error ) ) ;
}
2022-06-10 12:56:08 -04:00
2023-09-18 15:22:34 -04:00
void OnCanceled ( const TRequestWithStats < FCachePutRequest > & RequestWithStats )
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache put failed with canceled request for '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Record . GetKey ( ) ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Canceled ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Canceled ) ) ;
}
2022-06-10 12:56:08 -04:00
FZenCacheStore & CacheStore ;
IRequestOwner & Owner ;
2023-06-13 17:14:59 -04:00
TArray < TRequestWithStats < FCachePutRequest > , TInlineAllocator < 1 > > Requests ;
2022-06-10 12:56:08 -04:00
uint64 BatchSize = 0 ;
2023-06-13 17:14:59 -04:00
TBatchView < const TRequestWithStats < FCachePutRequest > > Batches ;
2022-06-10 12:56:08 -04:00
FOnCachePutComplete OnComplete ;
} ;
2022-07-18 12:23:16 -04:00
class FZenCacheStore : : FGetOp final : public FThreadSafeRefCountedObject
2022-06-10 12:56:08 -04:00
{
public :
FGetOp ( FZenCacheStore & InCacheStore ,
IRequestOwner & InOwner ,
const TConstArrayView < FCacheGetRequest > InRequests ,
FOnCacheGetComplete & & InOnComplete )
: CacheStore ( InCacheStore )
, Owner ( InOwner )
, OnComplete ( MoveTemp ( InOnComplete ) )
{
2023-06-13 17:14:59 -04:00
StartRequests ( Requests , InRequests , [ ] ( const FCacheGetRequest & Request ) { return Request . Key . Bucket ; } ,
[ ] ( auto & ) { return ERequestType : : Record ; } , ERequestOp : : Get ) ;
TRACE_COUNTER_ADD ( ZenDDC_Get , int64 ( Requests . Num ( ) ) ) ;
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_ADD ( ZenDDC_CacheRecordRequestCountInFlight , int64 ( Requests . Num ( ) ) ) ;
2022-06-10 12:56:08 -04:00
}
virtual ~ FGetOp ( )
{
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_SUBTRACT ( ZenDDC_CacheRecordRequestCountInFlight , int64 ( Requests . Num ( ) ) ) ;
2023-09-20 02:58:55 -04:00
FMonotonicTimeSpan AverageMainThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . MainThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageOtherThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . OtherThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageLatency = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . Latency . ToSeconds ( ) / Requests . Num ( ) ) ;
for ( TRequestWithStats < FCacheGetRequest > & Request : Requests )
{
Request . Stats . MainThreadTime = AverageMainThreadTime ;
Request . Stats . OtherThreadTime = AverageOtherThreadTime ;
Request . Stats . Latency = AverageLatency ;
}
2023-11-07 17:56:15 -05:00
CacheStore . ConditionalEvaluatePerformance ( ) ;
2024-01-09 06:08:29 -05:00
CacheStore . ConditionalUpdateStorageSize ( ) ;
2022-06-10 12:56:08 -04:00
}
void IssueRequests ( )
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2022-06-10 12:56:08 -04:00
FRequestBarrier Barrier ( Owner ) ;
ForEachBatch ( CacheStore . CacheRecordBatchSize , Requests . Num ( ) ,
[ this ] ( int32 BatchFirst , int32 BatchLast )
2023-06-13 17:14:59 -04:00
{
TConstArrayView < TRequestWithStats < FCacheGetRequest > > Batch ( Requests . GetData ( ) + BatchFirst , BatchLast - BatchFirst + 1 ) ;
FCbWriter BatchRequest ;
BatchRequest . BeginObject ( ) ;
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
BatchRequest < < ANSITEXTVIEW ( " Method " ) < < ANSITEXTVIEW ( " GetCacheRecords " ) ;
BatchRequest . AddInteger ( ANSITEXTVIEW ( " Accept " ) , Zen : : Http : : kCbPkgMagic ) ;
if ( CacheStore . bIsLocalConnection )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
BatchRequest . AddInteger ( ANSITEXTVIEW ( " AcceptFlags " ) , static_cast < uint32_t > ( Zen : : Http : : RpcAcceptOptions : : kAllowLocalReferences ) ) ;
BatchRequest . AddInteger ( ANSITEXTVIEW ( " Pid " ) , FPlatformProcess : : GetCurrentProcessId ( ) ) ;
}
2022-10-13 11:17:53 -04:00
2023-06-13 17:14:59 -04:00
BatchRequest . BeginObject ( ANSITEXTVIEW ( " Params " ) ) ;
{
ECachePolicy BatchDefaultPolicy = Batch [ 0 ] . Request . Policy . GetRecordPolicy ( ) ;
BatchRequest < < ANSITEXTVIEW ( " DefaultPolicy " ) < < * WriteToString < 128 > ( BatchDefaultPolicy ) ;
BatchRequest . AddString ( ANSITEXTVIEW ( " Namespace " ) , CacheStore . Namespace ) ;
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
BatchRequest . BeginArray ( ANSITEXTVIEW ( " Requests " ) ) ;
for ( const TRequestWithStats < FCacheGetRequest > & RequestWithStats : Batch )
{
BatchRequest . BeginObject ( ) ;
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
BatchRequest < < ANSITEXTVIEW ( " Key " ) < < RequestWithStats . Request . Key ;
2023-06-14 12:31:13 -04:00
if ( ( ! RequestWithStats . Request . Policy . IsUniform ( ) ) | | ( RequestWithStats . Request . Policy . GetRecordPolicy ( ) ! = BatchDefaultPolicy ) )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
BatchRequest < < ANSITEXTVIEW ( " Policy " ) < < RequestWithStats . Request . Policy ;
2022-06-10 12:56:08 -04:00
}
}
2023-06-13 17:14:59 -04:00
BatchRequest . EndObject ( ) ;
2022-06-10 12:56:08 -04:00
}
2023-06-13 17:14:59 -04:00
BatchRequest . EndArray ( ) ;
2022-06-10 12:56:08 -04:00
}
BatchRequest . EndObject ( ) ;
2023-06-13 17:14:59 -04:00
}
BatchRequest . EndObject ( ) ;
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
FGetOp * OriginalOp = this ;
auto OnRpcComplete = [ this , OpRef = TRefCountPtr < FGetOp > ( OriginalOp ) , Batch ] ( THttpUniquePtr < IHttpResponse > & HttpResponse , FCbPackage & Response )
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2023-11-07 17:56:15 -05:00
const FHttpResponseStats & ResponseStats = HttpResponse - > GetStats ( ) ;
Requests [ 0 ] . Stats . Latency = FMonotonicTimeSpan : : FromSeconds ( ResponseStats . StartTransferTime - ResponseStats . ConnectTime ) ;
2023-09-20 02:58:55 -04:00
2023-06-13 17:14:59 -04:00
int32 RequestIndex = 0 ;
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : None & & HttpResponse - > GetStatusCode ( ) > = 200 & & HttpResponse - > GetStatusCode ( ) < = 299 )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
const FCbObject & ResponseObj = Response . GetObject ( ) ;
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
for ( FCbField RecordField : ResponseObj [ ANSITEXTVIEW ( " Result " ) ] )
{
if ( RequestIndex > = Batch . Num ( ) )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
+ + RequestIndex ;
continue ;
2022-06-10 12:56:08 -04:00
}
2023-06-13 17:14:59 -04:00
const TRequestWithStats < FCacheGetRequest > & RequestWithStats = Batch [ RequestIndex + + ] ;
const FCacheKey & Key = RequestWithStats . Request . Key ;
FOptionalCacheRecord Record ;
if ( CacheStore . DebugOptions . ShouldSimulateGetMiss ( Key ) )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Simulated miss for put of '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( Key ) , * RequestWithStats . Request . Name ) ;
2022-06-10 12:56:08 -04:00
}
2023-06-13 17:14:59 -04:00
else if ( ! RecordField . IsNull ( ) )
{
Record = FCacheRecord : : Load ( Response , RecordField . AsObject ( ) ) ;
}
Record ? OnHit ( RequestWithStats , MoveTemp ( Record ) . Get ( ) ) : OnMiss ( RequestWithStats ) ;
2022-06-10 12:56:08 -04:00
}
2023-06-13 17:14:59 -04:00
if ( RequestIndex ! = Batch . Num ( ) )
2023-05-09 08:08:07 -04:00
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-06-13 17:14:59 -04:00
TEXT ( " %s: Invalid response received from GetCacheRecords RPC: %d results expected, received %d, from %s " ) ,
* CacheStore . GetName ( ) , Batch . Num ( ) , RequestIndex , * WriteToString < 256 > ( * HttpResponse ) ) ;
2023-05-09 08:08:07 -04:00
}
2023-06-13 17:14:59 -04:00
}
2023-09-18 15:22:34 -04:00
else if ( ( HttpResponse - > GetErrorCode ( ) ! = EHttpErrorCode : : Canceled ) & & ( HttpResponse - > GetStatusCode ( ) ! = 404 ) )
2023-06-13 17:14:59 -04:00
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-06-13 17:14:59 -04:00
TEXT ( " %s: Error response received from GetCacheRecords RPC: from %s " ) ,
* CacheStore . GetName ( ) , * WriteToString < 256 > ( * HttpResponse ) ) ;
}
2023-09-20 02:58:55 -04:00
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCacheGetRequest > & RequestWithStats : Batch . RightChop ( RequestIndex ) )
{
2023-09-18 15:22:34 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : Canceled )
{
OnCanceled ( RequestWithStats ) ;
}
else
{
OnMiss ( RequestWithStats ) ;
}
2023-06-13 17:14:59 -04:00
}
} ;
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
CacheStore . EnqueueAsyncRpc ( Owner , BatchRequest . Save ( ) . AsObject ( ) , MoveTemp ( OnRpcComplete ) ) ;
} ) ;
2022-06-10 12:56:08 -04:00
}
2023-06-13 17:14:59 -04:00
2022-06-10 12:56:08 -04:00
private :
2023-06-13 17:14:59 -04:00
void OnHit ( const TRequestWithStats < FCacheGetRequest > & RequestWithStats , FCacheRecord & & Record )
2022-06-10 12:56:08 -04:00
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache hit for '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
2023-06-15 04:54:40 -04:00
bool bInComplete = false ;
2023-06-13 17:14:59 -04:00
if ( const FCbObject & Meta = Record . GetMeta ( ) )
{
RequestWithStats . Stats . PhysicalReadSize + = Meta . GetSize ( ) ;
}
for ( const FValueWithId & Value : Record . GetValues ( ) )
{
RequestWithStats . Stats . AddLogicalRead ( Value ) ;
RequestWithStats . Stats . PhysicalReadSize + = Value . GetData ( ) . GetCompressedSize ( ) ;
2023-06-15 04:54:40 -04:00
ECachePolicy ValuePolicy = RequestWithStats . Request . Policy . GetValuePolicy ( Value . GetId ( ) ) ;
if ( EnumHasAnyFlags ( ValuePolicy , ECachePolicy : : SkipData ) )
{
continue ;
}
if ( Value . HasData ( ) )
{
continue ;
}
if ( EnumHasAnyFlags ( ValuePolicy , ECachePolicy : : Query ) )
{
bInComplete = true ;
2023-06-13 17:14:59 -04:00
}
2023-06-15 04:54:40 -04:00
}
EStatus Status = bInComplete ? EStatus : : Error : EStatus : : Ok ;
RequestWithStats . EndRequest ( CacheStore , Status ) ;
2022-06-10 12:56:08 -04:00
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_INCREMENT ( ZenDDC_GetHit ) ;
2023-06-13 17:14:59 -04:00
TRACE_COUNTER_ADD ( ZenDDC_BytesReceived , int64 ( RequestWithStats . Stats . PhysicalReadSize ) ) ;
2023-06-15 04:54:40 -04:00
OnComplete ( { RequestWithStats . Request . Name , MoveTemp ( Record ) , RequestWithStats . Request . UserData , Status } ) ;
2023-06-13 17:14:59 -04:00
}
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
void OnMiss ( const TRequestWithStats < FCacheGetRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache miss for '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Error ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Error ) ) ;
}
2022-06-10 12:56:08 -04:00
2023-09-18 15:22:34 -04:00
void OnCanceled ( const TRequestWithStats < FCacheGetRequest > & RequestWithStats )
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache miss with canceled request for '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Canceled ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Canceled ) ) ;
}
2022-06-10 12:56:08 -04:00
FZenCacheStore & CacheStore ;
IRequestOwner & Owner ;
2023-06-13 17:14:59 -04:00
TArray < TRequestWithStats < FCacheGetRequest > , TInlineAllocator < 1 > > Requests ;
2022-06-10 12:56:08 -04:00
FOnCacheGetComplete OnComplete ;
} ;
2022-07-18 12:23:16 -04:00
class FZenCacheStore : : FPutValueOp final : public FThreadSafeRefCountedObject
2022-06-10 12:56:08 -04:00
{
public :
FPutValueOp ( FZenCacheStore & InCacheStore ,
IRequestOwner & InOwner ,
const TConstArrayView < FCachePutValueRequest > InRequests ,
FOnCachePutValueComplete & & InOnComplete )
: CacheStore ( InCacheStore )
, Owner ( InOwner )
, OnComplete ( MoveTemp ( InOnComplete ) )
{
2023-06-13 17:14:59 -04:00
StartRequests ( Requests , InRequests , [ ] ( const FCachePutValueRequest & Request ) { return Request . Key . Bucket ; } ,
[ ] ( auto & ) { return ERequestType : : Value ; } , ERequestOp : : Put ) ;
TRACE_COUNTER_ADD ( ZenDDC_Put , int64 ( Requests . Num ( ) ) ) ;
Batches = TBatchView < const TRequestWithStats < FCachePutValueRequest > > ( Requests ,
[ this ] ( const TRequestWithStats < FCachePutValueRequest > & NextRequest ) { return BatchGroupingFilter ( NextRequest . Request ) ; } ) ;
2022-06-10 12:56:08 -04:00
}
2023-09-20 02:58:55 -04:00
virtual ~ FPutValueOp ( )
{
FMonotonicTimeSpan AverageMainThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . MainThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageOtherThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . OtherThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageLatency = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . Latency . ToSeconds ( ) / Requests . Num ( ) ) ;
for ( TRequestWithStats < FCachePutValueRequest > & Request : Requests )
{
Request . Stats . MainThreadTime = AverageMainThreadTime ;
Request . Stats . OtherThreadTime = AverageOtherThreadTime ;
Request . Stats . Latency = AverageLatency ;
}
2023-11-07 17:56:15 -05:00
CacheStore . ConditionalEvaluatePerformance ( ) ;
2024-01-09 06:08:29 -05:00
CacheStore . ConditionalUpdateStorageSize ( ) ;
2023-09-20 02:58:55 -04:00
}
2022-06-10 12:56:08 -04:00
void IssueRequests ( )
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2022-06-10 12:56:08 -04:00
FRequestBarrier Barrier ( Owner ) ;
2023-06-13 17:14:59 -04:00
for ( TArrayView < const TRequestWithStats < FCachePutValueRequest > > Batch : Batches )
2022-06-10 12:56:08 -04:00
{
FCbPackage BatchPackage ;
FCbWriter BatchWriter ;
BatchWriter . BeginObject ( ) ;
{
BatchWriter < < ANSITEXTVIEW ( " Method " ) < < ANSITEXTVIEW ( " PutCacheValues " ) ;
2022-10-13 11:17:53 -04:00
BatchWriter . AddInteger ( ANSITEXTVIEW ( " Accept " ) , Zen : : Http : : kCbPkgMagic ) ;
2022-06-10 12:56:08 -04:00
BatchWriter . BeginObject ( ANSITEXTVIEW ( " Params " ) ) ;
{
2023-06-13 17:14:59 -04:00
ECachePolicy BatchDefaultPolicy = Batch [ 0 ] . Request . Policy ;
2022-06-10 12:56:08 -04:00
BatchWriter < < ANSITEXTVIEW ( " DefaultPolicy " ) < < * WriteToString < 128 > ( BatchDefaultPolicy ) ;
2022-07-18 12:23:16 -04:00
BatchWriter . AddString ( ANSITEXTVIEW ( " Namespace " ) , CacheStore . Namespace ) ;
2022-06-10 12:56:08 -04:00
BatchWriter . BeginArray ( " Requests " ) ;
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCachePutValueRequest > & RequestWithStats : Batch )
2022-06-10 12:56:08 -04:00
{
BatchWriter . BeginObject ( ) ;
{
2023-06-13 17:14:59 -04:00
BatchWriter < < ANSITEXTVIEW ( " Key " ) < < RequestWithStats . Request . Key ;
const FValue & Value = RequestWithStats . Request . Value ;
2022-06-10 12:56:08 -04:00
BatchWriter . AddBinaryAttachment ( " RawHash " , Value . GetRawHash ( ) ) ;
if ( Value . HasData ( ) )
{
BatchPackage . AddAttachment ( FCbAttachment ( Value . GetData ( ) ) ) ;
}
2023-06-13 17:14:59 -04:00
if ( RequestWithStats . Request . Policy ! = BatchDefaultPolicy )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
BatchWriter < < ANSITEXTVIEW ( " Policy " ) < < WriteToString < 128 > ( RequestWithStats . Request . Policy ) ;
2022-06-10 12:56:08 -04:00
}
}
BatchWriter . EndObject ( ) ;
}
BatchWriter . EndArray ( ) ;
}
BatchWriter . EndObject ( ) ;
}
BatchWriter . EndObject ( ) ;
BatchPackage . SetObject ( BatchWriter . Save ( ) . AsObject ( ) ) ;
2022-07-18 12:23:16 -04:00
auto OnRpcComplete = [ this , OpRef = TRefCountPtr < FPutValueOp > ( this ) , Batch ] ( THttpUniquePtr < IHttpResponse > & HttpResponse , FCbPackage & Response )
2022-06-10 12:56:08 -04:00
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2023-11-07 17:56:15 -05:00
// Latency can't be measured for Put operations because it is intertwined with upload time.
Requests [ 0 ] . Stats . Latency = FMonotonicTimeSpan : : Infinity ( ) ;
2023-09-20 02:58:55 -04:00
2022-06-10 12:56:08 -04:00
int32 RequestIndex = 0 ;
2023-05-09 08:08:07 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : None & & HttpResponse - > GetStatusCode ( ) > = 200 & & HttpResponse - > GetStatusCode ( ) < = 299 )
2022-06-10 12:56:08 -04:00
{
const FCbObject & ResponseObj = Response . GetObject ( ) ;
for ( FCbField ResponseField : ResponseObj [ ANSITEXTVIEW ( " Result " ) ] )
{
if ( RequestIndex > = Batch . Num ( ) )
{
+ + RequestIndex ;
continue ;
}
2023-06-13 17:14:59 -04:00
const TRequestWithStats < FCachePutValueRequest > & RequestWithStats = Batch [ RequestIndex + + ] ;
2022-06-10 12:56:08 -04:00
bool bPutSucceeded = ResponseField . AsBool ( ) ;
2023-06-13 17:14:59 -04:00
if ( CacheStore . DebugOptions . ShouldSimulatePutMiss ( RequestWithStats . Request . Key ) )
2022-06-10 12:56:08 -04:00
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Simulated miss for PutValue of %s from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
2022-06-10 12:56:08 -04:00
bPutSucceeded = false ;
}
2023-06-13 17:14:59 -04:00
bPutSucceeded ? OnHit ( RequestWithStats ) : OnMiss ( RequestWithStats ) ;
2022-06-10 12:56:08 -04:00
}
if ( RequestIndex ! = Batch . Num ( ) )
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2022-07-21 23:01:51 -04:00
TEXT ( " %s: Invalid response received from PutCacheValues RPC: %d results expected, received %d, from %s " ) ,
* CacheStore . GetName ( ) , Batch . Num ( ) , RequestIndex , * WriteToString < 256 > ( * HttpResponse ) ) ;
2022-06-10 12:56:08 -04:00
}
}
2023-09-18 15:22:34 -04:00
else if ( ( HttpResponse - > GetErrorCode ( ) ! = EHttpErrorCode : : Canceled ) & & ( HttpResponse - > GetStatusCode ( ) ! = 404 ) )
2023-05-09 08:08:07 -04:00
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-05-09 08:08:07 -04:00
TEXT ( " %s: Error response received from PutCacheValues RPC: from %s " ) ,
* CacheStore . GetName ( ) , * WriteToString < 256 > ( * HttpResponse ) ) ;
}
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCachePutValueRequest > & RequestWithStats : Batch . RightChop ( RequestIndex ) )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : Canceled )
{
OnCanceled ( RequestWithStats ) ;
}
else
{
OnMiss ( RequestWithStats ) ;
}
2022-06-10 12:56:08 -04:00
}
} ;
2022-07-18 12:23:16 -04:00
CacheStore . EnqueueAsyncRpc ( Owner , BatchPackage , MoveTemp ( OnRpcComplete ) ) ;
2022-06-10 12:56:08 -04:00
}
}
private :
EBatchView BatchGroupingFilter ( const FCachePutValueRequest & NextRequest )
{
uint64 ValueSize = sizeof ( FCacheKey ) + NextRequest . Value . GetData ( ) . GetCompressedSize ( ) ;
BatchSize + = ValueSize ;
2023-11-25 16:22:26 -05:00
if ( BatchSize > CacheStore . MaxBatchPutKB * 1024 )
2022-06-10 12:56:08 -04:00
{
BatchSize = ValueSize ;
return EBatchView : : NewBatch ;
}
return EBatchView : : Continue ;
}
2023-06-13 17:14:59 -04:00
void OnHit ( const TRequestWithStats < FCachePutValueRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache put complete for %s from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
RequestWithStats . Stats . AddLogicalWrite ( RequestWithStats . Request . Value ) ;
RequestWithStats . Stats . PhysicalWriteSize + = RequestWithStats . Request . Value . GetData ( ) . GetCompressedSize ( ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Ok ) ;
TRACE_COUNTER_INCREMENT ( ZenDDC_PutHit ) ;
TRACE_COUNTER_ADD ( ZenDDC_BytesSent , RequestWithStats . Stats . PhysicalWriteSize ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Ok ) ) ;
}
void OnMiss ( const TRequestWithStats < FCachePutValueRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache put failed for '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Error ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Error ) ) ;
}
2022-06-10 12:56:08 -04:00
2023-09-18 15:22:34 -04:00
void OnCanceled ( const TRequestWithStats < FCachePutValueRequest > & RequestWithStats )
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache put failed with canceled request for '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Canceled ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Canceled ) ) ;
}
2022-06-10 12:56:08 -04:00
FZenCacheStore & CacheStore ;
IRequestOwner & Owner ;
2023-06-13 17:14:59 -04:00
TArray < TRequestWithStats < FCachePutValueRequest > , TInlineAllocator < 1 > > Requests ;
2022-06-10 12:56:08 -04:00
uint64 BatchSize = 0 ;
2023-06-13 17:14:59 -04:00
TBatchView < const TRequestWithStats < FCachePutValueRequest > > Batches ;
2022-06-10 12:56:08 -04:00
FOnCachePutValueComplete OnComplete ;
} ;
2022-07-18 12:23:16 -04:00
class FZenCacheStore : : FGetValueOp final : public FThreadSafeRefCountedObject
2022-06-10 12:56:08 -04:00
{
public :
FGetValueOp ( FZenCacheStore & InCacheStore ,
IRequestOwner & InOwner ,
const TConstArrayView < FCacheGetValueRequest > InRequests ,
FOnCacheGetValueComplete & & InOnComplete )
: CacheStore ( InCacheStore )
, Owner ( InOwner )
, OnComplete ( MoveTemp ( InOnComplete ) )
{
2023-06-13 17:14:59 -04:00
StartRequests ( Requests , InRequests , [ ] ( const FCacheGetValueRequest & Request ) { return Request . Key . Bucket ; } ,
[ ] ( auto & ) { return ERequestType : : Value ; } , ERequestOp : : Get ) ;
2022-06-10 12:56:08 -04:00
TRACE_COUNTER_ADD ( ZenDDC_Get , ( int64 ) Requests . Num ( ) ) ;
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_ADD ( ZenDDC_CacheRecordRequestCountInFlight , int64 ( Requests . Num ( ) ) ) ;
2022-06-10 12:56:08 -04:00
}
virtual ~ FGetValueOp ( )
{
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_SUBTRACT ( ZenDDC_CacheRecordRequestCountInFlight , int64 ( Requests . Num ( ) ) ) ;
2023-09-20 02:58:55 -04:00
FMonotonicTimeSpan AverageMainThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . MainThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageOtherThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . OtherThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageLatency = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . Latency . ToSeconds ( ) / Requests . Num ( ) ) ;
for ( TRequestWithStats < FCacheGetValueRequest > & Request : Requests )
{
Request . Stats . MainThreadTime = AverageMainThreadTime ;
Request . Stats . OtherThreadTime = AverageOtherThreadTime ;
Request . Stats . Latency = AverageLatency ;
}
2023-11-07 17:56:15 -05:00
CacheStore . ConditionalEvaluatePerformance ( ) ;
2024-01-09 06:08:29 -05:00
CacheStore . ConditionalUpdateStorageSize ( ) ;
2022-06-10 12:56:08 -04:00
}
void IssueRequests ( )
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2022-06-10 12:56:08 -04:00
FRequestBarrier Barrier ( Owner ) ;
ForEachBatch ( CacheStore . CacheRecordBatchSize , Requests . Num ( ) ,
[ this ] ( int32 BatchFirst , int32 BatchLast )
{
2023-06-13 17:14:59 -04:00
TConstArrayView < TRequestWithStats < FCacheGetValueRequest > > Batch ( Requests . GetData ( ) + BatchFirst , BatchLast - BatchFirst + 1 ) ;
2022-06-10 12:56:08 -04:00
FCbWriter BatchRequest ;
BatchRequest . BeginObject ( ) ;
{
BatchRequest < < ANSITEXTVIEW ( " Method " ) < < ANSITEXTVIEW ( " GetCacheValues " ) ;
2022-10-13 11:17:53 -04:00
BatchRequest . AddInteger ( ANSITEXTVIEW ( " Accept " ) , Zen : : Http : : kCbPkgMagic ) ;
2022-11-07 05:33:21 -05:00
if ( CacheStore . bIsLocalConnection )
{
BatchRequest . AddInteger ( ANSITEXTVIEW ( " AcceptFlags " ) , static_cast < uint32_t > ( Zen : : Http : : RpcAcceptOptions : : kAllowLocalReferences ) ) ;
2023-03-23 05:15:22 -04:00
BatchRequest . AddInteger ( ANSITEXTVIEW ( " Pid " ) , FPlatformProcess : : GetCurrentProcessId ( ) ) ;
2022-11-07 05:33:21 -05:00
}
2022-10-13 11:17:53 -04:00
2022-06-10 12:56:08 -04:00
BatchRequest . BeginObject ( ANSITEXTVIEW ( " Params " ) ) ;
{
2023-06-13 17:14:59 -04:00
ECachePolicy BatchDefaultPolicy = Batch [ 0 ] . Request . Policy ;
2022-06-10 12:56:08 -04:00
BatchRequest < < ANSITEXTVIEW ( " DefaultPolicy " ) < < * WriteToString < 128 > ( BatchDefaultPolicy ) ;
2022-07-18 12:23:16 -04:00
BatchRequest . AddString ( ANSITEXTVIEW ( " Namespace " ) , CacheStore . Namespace ) ;
2022-06-10 12:56:08 -04:00
BatchRequest . BeginArray ( " Requests " ) ;
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCacheGetValueRequest > & RequestWithStats : Batch )
2022-06-10 12:56:08 -04:00
{
BatchRequest . BeginObject ( ) ;
{
2023-06-13 17:14:59 -04:00
BatchRequest < < ANSITEXTVIEW ( " Key " ) < < RequestWithStats . Request . Key ;
if ( RequestWithStats . Request . Policy ! = BatchDefaultPolicy )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
BatchRequest < < ANSITEXTVIEW ( " Policy " ) < < WriteToString < 128 > ( RequestWithStats . Request . Policy ) ;
2022-06-10 12:56:08 -04:00
}
}
BatchRequest . EndObject ( ) ;
}
BatchRequest . EndArray ( ) ;
}
BatchRequest . EndObject ( ) ;
}
BatchRequest . EndObject ( ) ;
FGetValueOp * OriginalOp = this ;
2022-07-18 12:23:16 -04:00
auto OnRpcComplete = [ this , OpRef = TRefCountPtr < FGetValueOp > ( OriginalOp ) , Batch ] ( THttpUniquePtr < IHttpResponse > & HttpResponse , FCbPackage & Response )
2022-06-10 12:56:08 -04:00
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2023-11-07 17:56:15 -05:00
const FHttpResponseStats & ResponseStats = HttpResponse - > GetStats ( ) ;
Requests [ 0 ] . Stats . Latency = FMonotonicTimeSpan : : FromSeconds ( ResponseStats . StartTransferTime - ResponseStats . ConnectTime ) ;
2023-09-20 02:58:55 -04:00
2022-06-10 12:56:08 -04:00
int32 RequestIndex = 0 ;
2023-05-09 08:08:07 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : None & & HttpResponse - > GetStatusCode ( ) > = 200 & & HttpResponse - > GetStatusCode ( ) < = 299 )
2022-06-10 12:56:08 -04:00
{
const FCbObject & ResponseObj = Response . GetObject ( ) ;
for ( FCbFieldView ResultField : ResponseObj [ ANSITEXTVIEW ( " Result " ) ] )
{
if ( RequestIndex > = Batch . Num ( ) )
{
+ + RequestIndex ;
continue ;
}
2023-06-13 17:14:59 -04:00
const TRequestWithStats < FCacheGetValueRequest > & RequestWithStats = Batch [ RequestIndex + + ] ;
2022-06-10 12:56:08 -04:00
FCbObjectView ResultObj = ResultField . AsObjectView ( ) ;
TOptional < FValue > Value ;
2023-06-13 17:14:59 -04:00
if ( CacheStore . DebugOptions . ShouldSimulateGetMiss ( RequestWithStats . Request . Key ) )
2022-06-10 12:56:08 -04:00
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Simulated miss for GetValue of '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
2022-06-10 12:56:08 -04:00
}
else
{
FCbFieldView RawHashField = ResultObj [ " RawHash " ] ;
FIoHash RawHash = RawHashField . AsHash ( ) ;
2023-09-25 10:31:36 -04:00
const FCbAttachment * Attachment = EnumHasAnyFlags ( RequestWithStats . Request . Policy , ECachePolicy : : SkipData ) ? nullptr : Response . FindAttachment ( RawHash ) ;
if ( Attachment )
2022-06-10 12:56:08 -04:00
{
Value . Emplace ( Attachment - > AsCompressedBinary ( ) ) ;
}
else
{
FCbFieldView RawSizeField = ResultObj [ " RawSize " ] ;
uint64 RawSize = RawSizeField . AsUInt64 ( ) ;
if ( ! RawSizeField . HasError ( ) & & ! RawHashField . HasError ( ) )
{
Value . Emplace ( RawHash , RawSize ) ;
}
}
}
2023-06-13 17:14:59 -04:00
( bool ) Value ? OnHit ( RequestWithStats , MoveTemp ( * Value ) ) : OnMiss ( RequestWithStats ) ;
2022-06-10 12:56:08 -04:00
}
if ( RequestIndex ! = Batch . Num ( ) )
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2022-07-21 23:01:51 -04:00
TEXT ( " %s: Invalid response received from GetCacheValues RPC: %d results expected, received %d from %s " ) ,
* CacheStore . GetName ( ) , Batch . Num ( ) , RequestIndex , * WriteToString < 256 > ( * HttpResponse ) ) ;
2022-06-10 12:56:08 -04:00
}
}
2023-09-18 15:22:34 -04:00
else if ( ( HttpResponse - > GetErrorCode ( ) ! = EHttpErrorCode : : Canceled ) & & ( HttpResponse - > GetStatusCode ( ) ! = 404 ) )
2023-05-09 08:08:07 -04:00
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-05-09 08:08:07 -04:00
TEXT ( " %s: Error response received from GetCacheValues RPC: from %s " ) ,
* CacheStore . GetName ( ) , * WriteToString < 256 > ( * HttpResponse ) ) ;
}
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCacheGetValueRequest > & RequestWithStats : Batch . RightChop ( RequestIndex ) )
2022-06-10 12:56:08 -04:00
{
2023-09-18 15:22:34 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : Canceled )
{
OnCanceled ( RequestWithStats ) ;
}
else
{
OnMiss ( RequestWithStats ) ;
}
2022-06-10 12:56:08 -04:00
}
} ;
2022-07-18 12:23:16 -04:00
CacheStore . EnqueueAsyncRpc ( Owner , BatchRequest . Save ( ) . AsObject ( ) , MoveTemp ( OnRpcComplete ) ) ;
2022-06-10 12:56:08 -04:00
} ) ;
}
2023-06-13 17:14:59 -04:00
2022-06-10 12:56:08 -04:00
private :
2023-06-13 17:14:59 -04:00
void OnHit ( const TRequestWithStats < FCacheGetValueRequest > & RequestWithStats , FValue & & Value )
2022-06-10 12:56:08 -04:00
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache hit for '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
2022-06-10 12:56:08 -04:00
2023-06-13 17:14:59 -04:00
RequestWithStats . Stats . AddLogicalRead ( Value ) ;
RequestWithStats . Stats . PhysicalReadSize + = Value . GetData ( ) . GetCompressedSize ( ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Ok ) ;
TRACE_COUNTER_INCREMENT ( ZenDDC_GetHit ) ;
TRACE_COUNTER_ADD ( ZenDDC_BytesReceived , int64 ( RequestWithStats . Stats . PhysicalReadSize ) ) ;
OnComplete ( { RequestWithStats . Request . Name , RequestWithStats . Request . Key , MoveTemp ( Value ) , RequestWithStats . Request . UserData , EStatus : : Ok } ) ;
2022-06-10 12:56:08 -04:00
} ;
2023-06-13 17:14:59 -04:00
void OnMiss ( const TRequestWithStats < FCacheGetValueRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache miss for '%s' from '%s' " ) ,
2023-06-13 17:14:59 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Error ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Error ) ) ;
2022-06-10 12:56:08 -04:00
} ;
2023-09-18 15:22:34 -04:00
void OnCanceled ( const TRequestWithStats < FCacheGetValueRequest > & RequestWithStats )
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache miss with canceled request for '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( RequestWithStats . Request . Key ) , * RequestWithStats . Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Canceled ) ;
OnComplete ( RequestWithStats . Request . MakeResponse ( EStatus : : Canceled ) ) ;
} ;
2022-06-10 12:56:08 -04:00
FZenCacheStore & CacheStore ;
IRequestOwner & Owner ;
2023-06-13 17:14:59 -04:00
TArray < TRequestWithStats < FCacheGetValueRequest > , TInlineAllocator < 1 > > Requests ;
2022-06-10 12:56:08 -04:00
FOnCacheGetValueComplete OnComplete ;
} ;
2022-07-18 12:23:16 -04:00
class FZenCacheStore : : FGetChunksOp final : public FThreadSafeRefCountedObject
2022-06-10 12:56:08 -04:00
{
public :
FGetChunksOp ( FZenCacheStore & InCacheStore ,
IRequestOwner & InOwner ,
const TConstArrayView < FCacheGetChunkRequest > InRequests ,
FOnCacheGetChunkComplete & & InOnComplete )
: CacheStore ( InCacheStore )
, Owner ( InOwner )
, OnComplete ( MoveTemp ( InOnComplete ) )
{
2023-06-13 17:14:59 -04:00
StartRequests ( Requests , InRequests , [ ] ( const FCacheGetChunkRequest & Request ) { return Request . Key . Bucket ; } ,
[ ] ( const FCacheGetChunkRequest & Request ) { return Request . Id . IsNull ( ) ? ERequestType : : Value : ERequestType : : Record ; } ,
ERequestOp : : GetChunk ) ;
Algo : : StableSortBy ( Requests , & TRequestWithStats < FCacheGetChunkRequest > : : Request , TChunkLess ( ) ) ;
2022-06-10 12:56:08 -04:00
TRACE_COUNTER_ADD ( ZenDDC_Get , int64 ( Requests . Num ( ) ) ) ;
2023-06-13 17:14:59 -04:00
TRACE_COUNTER_ADD ( ZenDDC_ChunkRequestCountInFlight , int64 ( Requests . Num ( ) ) ) ;
2022-06-10 12:56:08 -04:00
}
virtual ~ FGetChunksOp ( )
{
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_SUBTRACT ( ZenDDC_ChunkRequestCountInFlight , int64 ( Requests . Num ( ) ) ) ;
2023-09-20 02:58:55 -04:00
FMonotonicTimeSpan AverageMainThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . MainThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageOtherThreadTime = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . OtherThreadTime . ToSeconds ( ) / Requests . Num ( ) ) ;
FMonotonicTimeSpan AverageLatency = FMonotonicTimeSpan : : FromSeconds ( Requests [ 0 ] . Stats . Latency . ToSeconds ( ) / Requests . Num ( ) ) ;
for ( TRequestWithStats < FCacheGetChunkRequest > & Request : Requests )
{
Request . Stats . MainThreadTime = AverageMainThreadTime ;
Request . Stats . OtherThreadTime = AverageOtherThreadTime ;
Request . Stats . Latency = AverageLatency ;
}
2023-11-07 17:56:15 -05:00
CacheStore . ConditionalEvaluatePerformance ( ) ;
2024-01-09 06:08:29 -05:00
CacheStore . ConditionalUpdateStorageSize ( ) ;
2022-06-10 12:56:08 -04:00
}
void IssueRequests ( )
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2022-06-10 12:56:08 -04:00
FRequestBarrier Barrier ( Owner ) ;
ForEachBatch ( CacheStore . CacheChunksBatchSize , Requests . Num ( ) ,
[ this ] ( int32 BatchFirst , int32 BatchLast )
{
2023-06-13 17:14:59 -04:00
TConstArrayView < TRequestWithStats < FCacheGetChunkRequest > > Batch ( Requests . GetData ( ) + BatchFirst , BatchLast - BatchFirst + 1 ) ;
2022-06-10 12:56:08 -04:00
FCbWriter BatchRequest ;
BatchRequest . BeginObject ( ) ;
{
BatchRequest < < ANSITEXTVIEW ( " Method " ) < < " GetCacheChunks " ;
2022-10-13 11:17:53 -04:00
BatchRequest . AddInteger ( ANSITEXTVIEW ( " Accept " ) , Zen : : Http : : kCbPkgMagic ) ;
2022-11-07 05:33:21 -05:00
if ( CacheStore . bIsLocalConnection )
{
BatchRequest . AddInteger ( ANSITEXTVIEW ( " AcceptFlags " ) , static_cast < uint32_t > ( Zen : : Http : : RpcAcceptOptions : : kAllowLocalReferences ) ) ;
2023-03-23 05:15:22 -04:00
BatchRequest . AddInteger ( ANSITEXTVIEW ( " Pid " ) , FPlatformProcess : : GetCurrentProcessId ( ) ) ;
2022-11-07 05:33:21 -05:00
}
2022-10-13 11:17:53 -04:00
2022-06-10 12:56:08 -04:00
BatchRequest . BeginObject ( ANSITEXTVIEW ( " Params " ) ) ;
{
2023-06-13 17:14:59 -04:00
ECachePolicy DefaultPolicy = Batch [ 0 ] . Request . Policy ;
2022-06-10 12:56:08 -04:00
BatchRequest < < ANSITEXTVIEW ( " DefaultPolicy " ) < < WriteToString < 128 > ( DefaultPolicy ) ;
2022-07-18 12:23:16 -04:00
BatchRequest . AddString ( ANSITEXTVIEW ( " Namespace " ) , CacheStore . Namespace ) ;
2022-06-10 12:56:08 -04:00
BatchRequest . BeginArray ( ANSITEXTVIEW ( " ChunkRequests " ) ) ;
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCacheGetChunkRequest > & RequestWithStats : Batch )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
const FCacheGetChunkRequest & Request = RequestWithStats . Request ;
2022-06-10 12:56:08 -04:00
BatchRequest . BeginObject ( ) ;
{
BatchRequest < < ANSITEXTVIEW ( " Key " ) < < Request . Key ;
if ( Request . Id . IsValid ( ) )
{
BatchRequest . AddObjectId ( ANSITEXTVIEW ( " ValueId " ) , Request . Id ) ;
}
if ( Request . RawOffset ! = 0 )
{
BatchRequest < < ANSITEXTVIEW ( " RawOffset " ) < < Request . RawOffset ;
}
if ( Request . RawSize ! = MAX_uint64 )
{
BatchRequest < < ANSITEXTVIEW ( " RawSize " ) < < Request . RawSize ;
}
if ( ! Request . RawHash . IsZero ( ) )
{
BatchRequest < < ANSITEXTVIEW ( " ChunkId " ) < < Request . RawHash ;
}
if ( Request . Policy ! = DefaultPolicy )
{
BatchRequest < < ANSITEXTVIEW ( " Policy " ) < < WriteToString < 128 > ( Request . Policy ) ;
}
}
BatchRequest . EndObject ( ) ;
}
BatchRequest . EndArray ( ) ;
}
BatchRequest . EndObject ( ) ;
}
BatchRequest . EndObject ( ) ;
2022-09-28 16:39:24 -04:00
FGetChunksOp * OriginalOp = this ;
auto OnRpcComplete = [ this , OpRef = TRefCountPtr < FGetChunksOp > ( OriginalOp ) , Batch ] ( THttpUniquePtr < IHttpResponse > & HttpResponse , FCbPackage & Response )
2022-06-10 12:56:08 -04:00
{
2023-09-20 02:58:55 -04:00
FRequestTimer RequestTimer ( Requests [ 0 ] . Stats ) ;
2023-11-07 17:56:15 -05:00
const FHttpResponseStats & ResponseStats = HttpResponse - > GetStats ( ) ;
Requests [ 0 ] . Stats . Latency = FMonotonicTimeSpan : : FromSeconds ( ResponseStats . StartTransferTime - ResponseStats . ConnectTime ) ;
2023-09-20 02:58:55 -04:00
2022-09-28 16:39:24 -04:00
int32 RequestIndex = 0 ;
2023-05-09 08:08:07 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : None & & HttpResponse - > GetStatusCode ( ) > = 200 & & HttpResponse - > GetStatusCode ( ) < = 299 )
2022-06-10 12:56:08 -04:00
{
2022-09-28 16:39:24 -04:00
const FCbObject & ResponseObj = Response . GetObject ( ) ;
for ( FCbFieldView ResultView : ResponseObj [ ANSITEXTVIEW ( " Result " ) ] )
2022-06-10 12:56:08 -04:00
{
2022-09-28 16:39:24 -04:00
if ( RequestIndex > = Batch . Num ( ) )
2022-06-10 12:56:08 -04:00
{
2022-09-28 16:39:24 -04:00
+ + RequestIndex ;
continue ;
}
2023-06-13 17:14:59 -04:00
const TRequestWithStats < FCacheGetChunkRequest > & RequestWithStats = Batch [ RequestIndex + + ] ;
2022-09-28 16:39:24 -04:00
FIoHash RawHash ;
bool Succeeded = false ;
uint64 RawSize = 0 ;
FCbObjectView ResultObject = ResultView . AsObjectView ( ) ;
FSharedBuffer RequestedBytes ;
2023-06-13 17:14:59 -04:00
const FCacheGetChunkRequest & Request = RequestWithStats . Request ;
2022-09-28 16:39:24 -04:00
if ( CacheStore . DebugOptions . ShouldSimulateGetMiss ( Request . Key ) )
{
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Simulated miss for get of '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( Request . Key , ' / ' , Request . Id ) , * Request . Name ) ;
}
else
{
FCbFieldView HashView = ResultObject [ ANSITEXTVIEW ( " RawHash " ) ] ;
RawHash = HashView . AsHash ( ) ;
if ( ! HashView . HasError ( ) )
2022-06-10 12:56:08 -04:00
{
2023-09-25 10:31:36 -04:00
const FCbAttachment * Attachment = EnumHasAnyFlags ( RequestWithStats . Request . Policy , ECachePolicy : : SkipData ) ? nullptr : Response . FindAttachment ( HashView . AsHash ( ) ) ;
if ( Attachment )
2022-06-10 12:56:08 -04:00
{
2022-09-28 16:39:24 -04:00
FCompressedBuffer CompressedBuffer = Attachment - > AsCompressedBinary ( ) ;
if ( CompressedBuffer )
{
TRACE_COUNTER_ADD ( ZenDDC_BytesReceived , CompressedBuffer . GetCompressedSize ( ) ) ;
RequestedBytes = FCompressedBufferReader ( CompressedBuffer ) . Decompress ( Request . RawOffset , Request . RawSize ) ;
RawSize = RequestedBytes . GetSize ( ) ;
Succeeded = true ;
}
2022-06-10 12:56:08 -04:00
}
2022-09-28 16:39:24 -04:00
else
2022-06-10 12:56:08 -04:00
{
2022-09-28 16:39:24 -04:00
FCbFieldView RawSizeField = ResultObject [ ANSITEXTVIEW ( " RawSize " ) ] ;
uint64 TotalSize = RawSizeField . AsUInt64 ( ) ;
Succeeded = ! RawSizeField . HasError ( ) ;
if ( Succeeded )
{
RawSize = FMath : : Min ( Request . RawSize , TotalSize - FMath : : Min ( Request . RawOffset , TotalSize ) ) ;
}
2022-06-10 12:56:08 -04:00
}
}
}
2023-06-13 17:14:59 -04:00
Succeeded ? OnHit ( RequestWithStats , MoveTemp ( RawHash ) , RawSize , MoveTemp ( RequestedBytes ) ) : OnMiss ( RequestWithStats ) ;
2022-06-10 12:56:08 -04:00
}
}
2023-09-18 15:22:34 -04:00
else if ( ( HttpResponse - > GetErrorCode ( ) ! = EHttpErrorCode : : Canceled ) & & ( HttpResponse - > GetStatusCode ( ) ! = 404 ) )
2023-05-09 08:08:07 -04:00
{
2023-09-29 17:36:33 -04:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-05-09 08:08:07 -04:00
TEXT ( " %s: Error response received from GetChunks RPC: from %s " ) ,
* CacheStore . GetName ( ) , * WriteToString < 256 > ( * HttpResponse ) ) ;
}
2023-06-13 17:14:59 -04:00
for ( const TRequestWithStats < FCacheGetChunkRequest > & RequestWithStats : Batch . RightChop ( RequestIndex ) )
2022-09-28 16:39:24 -04:00
{
2023-09-18 15:22:34 -04:00
if ( HttpResponse - > GetErrorCode ( ) = = EHttpErrorCode : : Canceled )
{
OnCanceled ( RequestWithStats ) ;
}
else
{
OnMiss ( RequestWithStats ) ;
}
2022-09-28 16:39:24 -04:00
}
} ;
CacheStore . EnqueueAsyncRpc ( Owner , BatchRequest . Save ( ) . AsObject ( ) , MoveTemp ( OnRpcComplete ) ) ;
2022-06-10 12:56:08 -04:00
} ) ;
}
2023-06-13 17:14:59 -04:00
2022-06-10 12:56:08 -04:00
private :
2023-06-13 17:14:59 -04:00
void OnHit ( const TRequestWithStats < FCacheGetChunkRequest > & RequestWithStats , FIoHash & & RawHash , uint64 RawSize , FSharedBuffer & & RequestedBytes )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
const FCacheGetChunkRequest & Request = RequestWithStats . Request ;
2023-09-18 15:22:34 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache hit for '%s' from '%s' " ) ,
2022-06-10 12:56:08 -04:00
* CacheStore . GetName ( ) , * WriteToString < 96 > ( Request . Key , ' / ' , Request . Id ) , * Request . Name ) ;
2023-06-13 17:14:59 -04:00
// This is a rough estimate of physical read size until Zen communicates stats with each response.
2023-09-20 02:58:55 -04:00
RequestWithStats . Stats . LogicalReadSize + = RawSize ;
2023-06-13 17:14:59 -04:00
RequestWithStats . Stats . PhysicalReadSize + = RequestedBytes . GetSize ( ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Ok ) ;
2023-02-14 03:09:44 -05:00
TRACE_COUNTER_INCREMENT ( ZenDDC_GetHit ) ;
2023-06-13 17:14:59 -04:00
TRACE_COUNTER_ADD ( ZenDDC_BytesReceived , int64 ( RequestWithStats . Stats . PhysicalReadSize ) ) ;
2022-06-10 12:56:08 -04:00
OnComplete ( { Request . Name , Request . Key , Request . Id , Request . RawOffset ,
RawSize , MoveTemp ( RawHash ) , MoveTemp ( RequestedBytes ) , Request . UserData , EStatus : : Ok } ) ;
} ;
2023-06-13 17:14:59 -04:00
void OnMiss ( const TRequestWithStats < FCacheGetChunkRequest > & RequestWithStats )
2022-06-10 12:56:08 -04:00
{
2023-06-13 17:14:59 -04:00
const FCacheGetChunkRequest & Request = RequestWithStats . Request ;
2023-09-18 15:22:34 -04:00
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache miss with missing value '%s' for '%s' from '%s' " ) ,
2022-06-10 12:56:08 -04:00
* CacheStore . GetName ( ) , * WriteToString < 16 > ( Request . Id ) , * WriteToString < 96 > ( Request . Key ) , * Request . Name ) ;
2023-06-13 17:14:59 -04:00
RequestWithStats . EndRequest ( CacheStore , EStatus : : Error ) ;
2022-06-10 12:56:08 -04:00
OnComplete ( Request . MakeResponse ( EStatus : : Error ) ) ;
} ;
2023-09-18 15:22:34 -04:00
void OnCanceled ( const TRequestWithStats < FCacheGetChunkRequest > & RequestWithStats )
{
const FCacheGetChunkRequest & Request = RequestWithStats . Request ;
UE_LOG ( LogDerivedDataCache , Verbose , TEXT ( " %s: Cache miss with canceled request for '%s' from '%s' " ) ,
* CacheStore . GetName ( ) , * WriteToString < 96 > ( Request . Key , ' / ' , Request . Id ) , * Request . Name ) ;
RequestWithStats . EndRequest ( CacheStore , EStatus : : Canceled ) ;
OnComplete ( Request . MakeResponse ( EStatus : : Canceled ) ) ;
} ;
2022-06-10 12:56:08 -04:00
FZenCacheStore & CacheStore ;
IRequestOwner & Owner ;
2023-06-13 17:14:59 -04:00
TArray < TRequestWithStats < FCacheGetChunkRequest > , TInlineAllocator < 1 > > Requests ;
2022-06-10 12:56:08 -04:00
FOnCacheGetChunkComplete OnComplete ;
} ;
2023-12-13 11:34:21 -05:00
class FZenCacheStore : : FHealthReceiver final : public IHttpReceiver
2023-11-07 17:56:15 -05:00
{
public :
2023-12-13 11:34:21 -05:00
FHealthReceiver ( const FHealthReceiver & ) = delete ;
FHealthReceiver & operator = ( const FHealthReceiver & ) = delete ;
2023-11-07 17:56:15 -05:00
2024-01-18 22:43:41 -05:00
explicit FHealthReceiver ( EHealth & OutHealth , FString * OutResponseBody = nullptr , IHttpReceiver * InNext = nullptr )
2023-12-13 11:34:21 -05:00
: Health ( OutHealth )
2024-01-18 22:43:41 -05:00
, ResponseBody ( OutResponseBody )
2023-11-07 17:56:15 -05:00
, Next ( InNext )
{
2023-12-13 11:34:21 -05:00
Health = EHealth : : Unknown ;
2023-11-07 17:56:15 -05:00
}
private :
IHttpReceiver * OnCreate ( IHttpResponse & Response ) final
{
return & BodyReceiver ;
}
IHttpReceiver * OnComplete ( IHttpResponse & Response ) final
{
FUtf8StringView ResponseStringView ( reinterpret_cast < const UTF8CHAR * > ( BodyArray . GetData ( ) ) , IntCastChecked < int32 > ( BodyArray . Num ( ) ) ) ;
if ( ResponseStringView = = UTF8TEXTVIEW ( " OK! " ) )
{
2023-12-13 11:34:21 -05:00
Health = EHealth : : Ok ;
2023-11-07 17:56:15 -05:00
}
else
{
2023-12-13 11:34:21 -05:00
Health = EHealth : : Error ;
2023-11-07 17:56:15 -05:00
}
2024-01-18 22:43:41 -05:00
if ( ResponseBody )
{
* ResponseBody = * WriteToString < 64 > ( ResponseStringView ) ;
}
2023-11-07 17:56:15 -05:00
return Next ;
}
private :
2023-12-13 11:34:21 -05:00
EHealth & Health ;
2024-01-18 22:43:41 -05:00
FString * ResponseBody ;
2023-11-07 17:56:15 -05:00
IHttpReceiver * Next ;
TArray64 < uint8 > BodyArray ;
FHttpByteArrayReceiver BodyReceiver { BodyArray , this } ;
} ;
2023-12-13 11:34:21 -05:00
class FZenCacheStore : : FAsyncHealthReceiver final : public FRequestBase , public IHttpReceiver
2023-11-07 17:56:15 -05:00
{
public :
2023-12-13 11:34:21 -05:00
FAsyncHealthReceiver ( const FAsyncHealthReceiver & ) = delete ;
FAsyncHealthReceiver & operator = ( const FAsyncHealthReceiver & ) = delete ;
2023-11-07 17:56:15 -05:00
2023-12-13 11:34:21 -05:00
FAsyncHealthReceiver (
2023-11-07 17:56:15 -05:00
THttpUniquePtr < IHttpRequest > & & InRequest ,
IRequestOwner * InOwner ,
Zen : : FZenServiceInstance & InZenServiceInstance ,
2023-12-13 11:34:21 -05:00
FOnHealthComplete & & InOnHealthComplete )
2023-11-07 17:56:15 -05:00
: Request ( MoveTemp ( InRequest ) )
, Owner ( InOwner )
, ZenServiceInstance ( InZenServiceInstance )
2024-01-18 22:43:41 -05:00
, BaseReceiver ( Health , nullptr , this )
2023-12-13 11:34:21 -05:00
, OnHealthComplete ( MoveTemp ( InOnHealthComplete ) )
2023-11-07 17:56:15 -05:00
{
Request - > SendAsync ( this , Response ) ;
}
private :
// IRequest Interface
void SetPriority ( EPriority Priority ) final { }
void Cancel ( ) final { Monitor - > Cancel ( ) ; }
void Wait ( ) final { Monitor - > Wait ( ) ; }
// IHttpReceiver Interface
IHttpReceiver * OnCreate ( IHttpResponse & LocalResponse ) final
{
Monitor = LocalResponse . GetMonitor ( ) ;
Owner - > Begin ( this ) ;
return & BaseReceiver ;
}
bool ShouldRecoverAndRetry ( IHttpResponse & LocalResponse )
{
if ( ! ZenServiceInstance . IsServiceRunningLocally ( ) )
{
return false ;
}
if ( ( LocalResponse . GetErrorCode ( ) = = EHttpErrorCode : : Connect ) | |
( LocalResponse . GetErrorCode ( ) = = EHttpErrorCode : : TlsConnect ) | |
( LocalResponse . GetErrorCode ( ) = = EHttpErrorCode : : TimedOut ) )
{
return true ;
}
return false ;
}
IHttpReceiver * OnComplete ( IHttpResponse & LocalResponse ) final
{
Owner - > End ( this , [ Self = this , & LocalResponse ]
{
if ( Self - > ShouldRecoverAndRetry ( LocalResponse ) & & Self - > ZenServiceInstance . TryRecovery ( ) )
{
2023-12-13 11:34:21 -05:00
new FAsyncHealthReceiver ( MoveTemp ( Self - > Request ) , Self - > Owner , Self - > ZenServiceInstance , MoveTemp ( Self - > OnHealthComplete ) ) ;
2023-11-07 17:56:15 -05:00
return ;
}
Self - > Request . Reset ( ) ;
2023-12-13 11:34:21 -05:00
if ( Self - > OnHealthComplete )
2023-11-07 17:56:15 -05:00
{
// Launch a task for the completion function since it can execute arbitrary code.
2023-12-13 11:34:21 -05:00
Self - > Owner - > LaunchTask ( TEXT ( " ZenHealthComplete " ) , [ Self = TRefCountPtr ( Self ) ]
2023-11-07 17:56:15 -05:00
{
// Ensuring that the OnRpcComplete method is destroyed by the time we exit this method by moving it to a local scope variable
2023-12-13 11:34:21 -05:00
FOnHealthComplete LocalOnComplete = MoveTemp ( Self - > OnHealthComplete ) ;
LocalOnComplete ( Self - > Response , Self - > Health ) ;
2023-11-07 17:56:15 -05:00
} ) ;
}
} ) ;
return nullptr ;
}
private :
THttpUniquePtr < IHttpRequest > Request ;
THttpUniquePtr < IHttpResponse > Response ;
TRefCountPtr < IHttpResponseMonitor > Monitor ;
IRequestOwner * Owner ;
Zen : : FZenServiceInstance & ZenServiceInstance ;
2023-12-13 11:34:21 -05:00
EHealth Health ;
FHealthReceiver BaseReceiver ;
FOnHealthComplete OnHealthComplete ;
2023-11-07 17:56:15 -05:00
} ;
2022-07-18 12:23:16 -04:00
class FZenCacheStore : : FCbPackageReceiver final : public IHttpReceiver
{
public :
FCbPackageReceiver ( const FCbPackageReceiver & ) = delete ;
FCbPackageReceiver & operator = ( const FCbPackageReceiver & ) = delete ;
explicit FCbPackageReceiver ( FCbPackage & OutPackage , IHttpReceiver * InNext = nullptr )
: Package ( OutPackage )
, Next ( InNext )
{
}
private :
IHttpReceiver * OnCreate ( IHttpResponse & Response ) final
{
return & BodyReceiver ;
}
IHttpReceiver * OnComplete ( IHttpResponse & Response ) final
{
2022-09-28 18:22:23 -04:00
FMemoryView MemoryView = MakeMemoryView ( BodyArray ) ;
{
FMemoryReaderView Ar ( MemoryView ) ;
if ( Zen : : Http : : TryLoadCbPackage ( Package , Ar ) )
{
return Next ;
}
}
FMemoryReaderView Ar ( MemoryView ) ;
2022-07-18 12:23:16 -04:00
Package . TryLoad ( Ar ) ;
return Next ;
}
private :
FCbPackage & Package ;
IHttpReceiver * Next ;
TArray64 < uint8 > BodyArray ;
FHttpByteArrayReceiver BodyReceiver { BodyArray , this } ;
} ;
class FZenCacheStore : : FAsyncCbPackageReceiver final : public FRequestBase , public IHttpReceiver
{
public :
FAsyncCbPackageReceiver ( const FAsyncCbPackageReceiver & ) = delete ;
FAsyncCbPackageReceiver & operator = ( const FAsyncCbPackageReceiver & ) = delete ;
FAsyncCbPackageReceiver (
THttpUniquePtr < IHttpRequest > & & InRequest ,
IRequestOwner * InOwner ,
2022-12-16 15:47:14 -05:00
Zen : : FZenServiceInstance & InZenServiceInstance ,
2022-07-18 12:23:16 -04:00
FOnRpcComplete & & InOnRpcComplete )
: Request ( MoveTemp ( InRequest ) )
, Owner ( InOwner )
2022-12-16 15:47:14 -05:00
, ZenServiceInstance ( InZenServiceInstance )
2022-07-18 12:23:16 -04:00
, BaseReceiver ( Package , this )
, OnRpcComplete ( MoveTemp ( InOnRpcComplete ) )
{
Request - > SendAsync ( this , Response ) ;
}
private :
// IRequest Interface
void SetPriority ( EPriority Priority ) final { }
void Cancel ( ) final { Monitor - > Cancel ( ) ; }
void Wait ( ) final { Monitor - > Wait ( ) ; }
// IHttpReceiver Interface
IHttpReceiver * OnCreate ( IHttpResponse & LocalResponse ) final
{
Monitor = LocalResponse . GetMonitor ( ) ;
Owner - > Begin ( this ) ;
return & BaseReceiver ;
}
2022-12-16 15:47:14 -05:00
bool ShouldRecoverAndRetry ( IHttpResponse & LocalResponse )
{
if ( ! ZenServiceInstance . IsServiceRunningLocally ( ) )
{
return false ;
}
if ( ( LocalResponse . GetErrorCode ( ) = = EHttpErrorCode : : Connect ) | |
( LocalResponse . GetErrorCode ( ) = = EHttpErrorCode : : TlsConnect ) | |
( LocalResponse . GetErrorCode ( ) = = EHttpErrorCode : : TimedOut ) )
{
return true ;
}
return false ;
}
2022-07-18 12:23:16 -04:00
IHttpReceiver * OnComplete ( IHttpResponse & LocalResponse ) final
{
2022-12-16 15:47:14 -05:00
Owner - > End ( this , [ Self = this , & LocalResponse ]
2022-07-18 12:23:16 -04:00
{
2022-12-16 15:47:14 -05:00
if ( Self - > ShouldRecoverAndRetry ( LocalResponse ) & & Self - > ZenServiceInstance . TryRecovery ( ) )
{
new FAsyncCbPackageReceiver ( MoveTemp ( Self - > Request ) , Self - > Owner , Self - > ZenServiceInstance , MoveTemp ( Self - > OnRpcComplete ) ) ;
return ;
}
Self - > Request . Reset ( ) ;
2022-07-18 12:23:16 -04:00
if ( Self - > OnRpcComplete )
{
// Launch a task for the completion function since it can execute arbitrary code.
Self - > Owner - > LaunchTask ( TEXT ( " ZenHttpComplete " ) , [ Self = TRefCountPtr ( Self ) ]
{
2023-11-01 10:33:43 -04:00
// Ensuring that the OnRpcComplete method is destroyed by the time we exit this method by moving it to a local scope variable
FOnRpcComplete LocalOnComplete = MoveTemp ( Self - > OnRpcComplete ) ;
LocalOnComplete ( Self - > Response , Self - > Package ) ;
2022-07-18 12:23:16 -04:00
} ) ;
}
} ) ;
return nullptr ;
}
private :
THttpUniquePtr < IHttpRequest > Request ;
THttpUniquePtr < IHttpResponse > Response ;
TRefCountPtr < IHttpResponseMonitor > Monitor ;
IRequestOwner * Owner ;
2022-12-16 15:47:14 -05:00
Zen : : FZenServiceInstance & ZenServiceInstance ;
2022-07-18 12:23:16 -04:00
FCbPackage Package ;
FCbPackageReceiver BaseReceiver ;
FOnRpcComplete OnRpcComplete ;
} ;
2022-05-30 18:14:02 -04:00
FZenCacheStore : : FZenCacheStore (
2023-11-25 16:22:26 -05:00
const FZenCacheStoreParams & InParams ,
2023-06-13 17:14:59 -04:00
ICacheStoreOwner * InStoreOwner )
2023-11-25 16:22:26 -05:00
: ZenService ( * InParams . Host )
2023-06-13 17:14:59 -04:00
, StoreOwner ( InStoreOwner )
2023-11-07 17:56:15 -05:00
, PerformanceEvaluationRequestOwner ( EPriority : : Low )
2022-05-30 18:14:02 -04:00
{
2023-11-25 16:22:26 -05:00
Initialize ( InParams ) ;
2023-01-03 15:58:30 -05:00
}
FZenCacheStore : : FZenCacheStore (
UE : : Zen : : FServiceSettings & & InSettings ,
2023-11-25 16:22:26 -05:00
const FZenCacheStoreParams & InParams ,
2023-06-13 17:14:59 -04:00
ICacheStoreOwner * InStoreOwner )
2023-01-03 15:58:30 -05:00
: ZenService ( MoveTemp ( InSettings ) )
2023-06-13 17:14:59 -04:00
, StoreOwner ( InStoreOwner )
2023-11-07 17:56:15 -05:00
, PerformanceEvaluationRequestOwner ( EPriority : : Low )
2023-01-03 15:58:30 -05:00
{
2023-11-25 16:22:26 -05:00
Initialize ( InParams ) ;
2023-01-03 15:58:30 -05:00
}
2023-06-14 10:12:47 -04:00
FZenCacheStore : : ~ FZenCacheStore ( )
{
2023-11-07 17:56:15 -05:00
PerformanceEvaluationRequestOwner . Cancel ( ) ;
if ( PerformanceEvaluationThread . IsSet ( ) )
{
PerformanceEvaluationThreadShutdownEvent . Notify ( ) ;
PerformanceEvaluationThread - > Join ( ) ;
PerformanceEvaluationThread . Reset ( ) ;
PerformanceEvaluationThreadShutdownEvent . Reset ( ) ;
}
2023-06-14 10:12:47 -04:00
if ( StoreStats )
{
StoreOwner - > DestroyStats ( StoreStats ) ;
}
}
2023-11-25 16:22:26 -05:00
void FZenCacheStore : : Initialize ( const FZenCacheStoreParams & Params )
2023-01-03 15:58:30 -05:00
{
2024-01-18 22:43:41 -05:00
NodeName = Params . Name ;
2023-11-07 17:56:15 -05:00
LastPerformanceEvaluationTicks . store ( FDateTime : : UtcNow ( ) . GetTicks ( ) , std : : memory_order_relaxed ) ;
2024-01-09 06:08:29 -05:00
LastStorageSizeUpdateTicks . store ( FDateTime : : UtcNow ( ) . GetTicks ( ) , std : : memory_order_relaxed ) ;
2023-11-25 16:22:26 -05:00
Namespace = Params . Namespace ;
2023-12-13 11:34:21 -05:00
RpcUri < < ZenService . GetInstance ( ) . GetURL ( ) < < ANSITEXTVIEW ( " /z$/$rpc " ) ;
const uint32 MaxConnections = uint32 ( FMath : : Clamp ( FPlatformMisc : : NumberOfCoresIncludingHyperthreads ( ) , 8 , 64 ) ) ;
constexpr uint32 RequestPoolSize = 128 ;
constexpr uint32 RequestPoolOverflowSize = 128 ;
FHttpConnectionPoolParams ConnectionPoolParams ;
ConnectionPoolParams . MaxConnections = MaxConnections ;
ConnectionPoolParams . MinConnections = MaxConnections ;
ConnectionPool = IHttpManager : : Get ( ) . CreateConnectionPool ( ConnectionPoolParams ) ;
bool bReady = false ;
2022-05-30 18:14:02 -04:00
{
2023-12-13 11:34:21 -05:00
// Issue a synchronous health/ready request with a limited idle time
FHttpClientParams ReadinessClientParams ;
ReadinessClientParams . Version = EHttpVersion : : V2 ;
ReadinessClientParams . MaxRequests = 1 ;
ReadinessClientParams . MinRequests = 1 ;
ReadinessClientParams . LowSpeedLimit = 1 ;
ReadinessClientParams . LowSpeedTime = 5 ; // 5 second idle time limit for the initial readiness check
THttpUniquePtr < IHttpClient > ReadinessClient = ConnectionPool - > CreateClient ( ReadinessClientParams ) ;
THttpUniquePtr < IHttpRequest > ReadinessRequest = ReadinessClient - > TryCreateRequest ( { } ) ;
TAnsiStringBuilder < 256 > StatusUri ;
StatusUri < < ZenService . GetInstance ( ) . GetURL ( ) < < ANSITEXTVIEW ( " /health/ready " ) ;
ReadinessRequest - > SetUri ( StatusUri ) ;
ReadinessRequest - > SetMethod ( EHttpMethod : : Get ) ;
ReadinessRequest - > AddAcceptType ( EHttpMediaType : : Text ) ;
2023-12-13 13:17:25 -05:00
EHealth Health = EHealth : : Unknown ;
2024-01-18 22:43:41 -05:00
FString ResponseString ;
FHealthReceiver HealthReceiver ( Health , & ResponseString ) ;
2023-12-13 11:34:21 -05:00
THttpUniquePtr < IHttpResponse > ReadinessResponse ;
ReadinessRequest - > Send ( & HealthReceiver , ReadinessResponse ) ;
2024-01-17 01:34:02 -05:00
bReady = Health = = EHealth : : Ok ; // -V547
2024-01-18 22:43:41 -05:00
if ( ReadinessResponse - > GetErrorCode ( ) = = EHttpErrorCode : : None & &
( ReadinessResponse - > GetStatusCode ( ) > = 200 & & ReadinessResponse - > GetStatusCode ( ) < = 299 ) )
{
UE_LOG ( LogDerivedDataCache , Display ,
TEXT ( " %s: Using ZenServer HTTP service at %s with namespace %s status: %s. " ) ,
* GetName ( ) , ZenService . GetInstance ( ) . GetURL ( ) , * Namespace , * ResponseString ) ;
}
else
{
if ( ZenService . GetInstance ( ) . IsServiceRunningLocally ( ) )
{
UE_LOG ( LogDerivedDataCache , Warning ,
TEXT ( " %s: Unable to reach ZenServer HTTP service at %s with namespace %s. Status: %d . Response: %s " ) ,
* GetName ( ) , ZenService . GetInstance ( ) . GetURL ( ) , * Namespace , ReadinessResponse - > GetStatusCode ( ) ,
* ResponseString ) ;
}
else
{
UE_LOG ( LogDerivedDataCache , Display ,
TEXT ( " %s: Unable to reach ZenServer HTTP service at %s with namespace %s. Status: %d . Response: %s " ) ,
* GetName ( ) , ZenService . GetInstance ( ) . GetURL ( ) , * Namespace , ReadinessResponse - > GetStatusCode ( ) ,
* ResponseString ) ;
}
}
2023-12-13 11:34:21 -05:00
}
2022-07-18 12:23:16 -04:00
2023-12-13 11:34:21 -05:00
FHttpClientParams ClientParams ;
ClientParams . MaxRequests = RequestPoolSize + RequestPoolOverflowSize ;
ClientParams . MinRequests = RequestPoolSize ;
ClientParams . LowSpeedLimit = 1 ;
ClientParams . LowSpeedTime = 25 ;
RequestQueue = FHttpRequestQueue ( * ConnectionPool , ClientParams ) ;
2022-07-18 12:23:16 -04:00
2024-03-05 11:24:22 -05:00
bIsLocalConnection = ZenService . GetInstance ( ) . IsServiceRunningLocally ( ) | | ZenService . GetInstance ( ) . GetServiceSettings ( ) . IsAutoLaunch ( ) ;
2023-12-13 11:34:21 -05:00
bIsUsable = true ;
2022-07-18 12:23:16 -04:00
2023-12-13 11:34:21 -05:00
if ( StoreOwner )
{
// Default to locally launched service getting the Local cache store flag. Can be overridden by explicit value in config.
bool bLocal = Params . bLocal . Get ( bIsLocalConnection ) ;
2022-05-30 18:14:02 -04:00
2023-12-13 11:34:21 -05:00
// Default to non-locally launched service getting the Remote cache store flag. Can be overridden by explicit value in config.
// In the future this could be extended to allow the Remote flag by default (even for locally launched instances) if they have upstreams configured.
bool bRemote = Params . bRemote . Get ( ! bIsLocalConnection ) ;
DeactivateAtMs = Params . DeactivateAtMs ;
ECacheStoreFlags Flags = ECacheStoreFlags : : Query ;
Flags | = Params . bReadOnly ? ECacheStoreFlags : : None : ECacheStoreFlags : : Store ;
Flags | = bLocal ? ECacheStoreFlags : : Local : ECacheStoreFlags : : None ;
Flags | = bRemote ? ECacheStoreFlags : : Remote : ECacheStoreFlags : : None ;
OperationalFlags = Flags ;
if ( ! bReady )
2023-06-13 17:14:59 -04:00
{
2024-03-05 11:24:22 -05:00
Flags = OperationalFlags & ~ ( ECacheStoreFlags : : Store | ECacheStoreFlags : : Query ) ;
if ( bIsLocalConnection )
{
UE_LOG ( LogDerivedDataCache , Display ,
TEXT ( " %s: Readiness check failed. "
" It will be deactivated until responsiveness improves. "
" If this is consistent, consider disabling this cache store through "
" the use of the '-ddc=NoZenLocalFallback' or '-ddc=InstalledNoZenLocalFallback' "
" commandline arguments. " ) ,
* GetName ( ) ) ;
}
else
{
UE_LOG ( LogDerivedDataCache , Display ,
TEXT ( " %s: Readiness check failed. "
" It will be deactivated until responsiveness improves. "
" If this is consistent, consider disabling this cache store through "
" environment variables or other configuration. " ) ,
* GetName ( ) ) ;
}
2023-12-13 11:34:21 -05:00
bDeactivatedForPerformance . store ( true , std : : memory_order_relaxed ) ;
2023-06-13 17:14:59 -04:00
}
2023-12-13 11:34:21 -05:00
StoreOwner - > Add ( this , Flags ) ;
2024-01-09 06:08:29 -05:00
TStringBuilder < 256 > Path ( InPlace , ZenService . GetInstance ( ) . GetPath ( ) , TEXTVIEW ( " ( " ) , Namespace , TEXTVIEW ( " ) " ) ) ;
2023-12-13 11:34:21 -05:00
StoreStats = StoreOwner - > CreateStats ( this , Flags , TEXT ( " Zen " ) , * Params . Name , Path ) ;
bTryEvaluatePerformance = ! GIsBuildMachine & & ( StoreStats ! = nullptr ) & & ( DeactivateAtMs > 0.0f ) ;
StoreStats - > SetAttribute ( TEXTVIEW ( " Namespace " ) , Namespace ) ;
if ( ! bReady )
{
UpdateStatus ( ) ;
ActivatePerformanceEvaluationThread ( ) ;
}
2022-05-30 18:14:02 -04:00
}
2023-12-13 11:34:21 -05:00
// Issue a request for stats as it will be fetched asynchronously and issuing now makes them available sooner for future callers.
Zen : : FZenCacheStats ZenStats ;
ZenService . GetInstance ( ) . GetCacheStats ( ZenStats ) ;
2023-11-25 16:22:26 -05:00
MaxBatchPutKB = Params . MaxBatchPutKB ;
CacheRecordBatchSize = Params . RecordBatchSize ;
CacheChunksBatchSize = Params . ChunksBatchSize ;
2022-05-30 18:14:02 -04:00
}
bool FZenCacheStore : : IsServiceReady ( )
{
return ZenService . GetInstance ( ) . IsServiceReady ( ) ;
}
2022-07-18 12:23:16 -04:00
FCompositeBuffer FZenCacheStore : : SaveRpcPackage ( const FCbPackage & Package )
2022-05-31 12:42:17 -04:00
{
2022-07-18 12:23:16 -04:00
FLargeMemoryWriter Memory ;
Zen : : Http : : SaveCbPackage ( Package , Memory ) ;
uint64 PackageMemorySize = Memory . TotalSize ( ) ;
return FCompositeBuffer ( FSharedBuffer : : TakeOwnership ( Memory . ReleaseOwnership ( ) , PackageMemorySize , FMemory : : Free ) ) ;
2022-05-31 12:42:17 -04:00
}
2022-07-18 12:23:16 -04:00
THttpUniquePtr < IHttpRequest > FZenCacheStore : : CreateRpcRequest ( )
2022-05-31 12:42:17 -04:00
{
2022-07-18 12:23:16 -04:00
THttpUniquePtr < IHttpRequest > Request = RequestQueue . CreateRequest ( { } ) ;
Request - > SetUri ( RpcUri ) ;
Request - > SetMethod ( EHttpMethod : : Post ) ;
Request - > AddAcceptType ( EHttpMediaType : : CbPackage ) ;
return Request ;
2022-05-31 12:42:17 -04:00
}
2022-07-18 12:23:16 -04:00
void FZenCacheStore : : EnqueueAsyncRpc ( IRequestOwner & Owner , FCbObject RequestObject , FOnRpcComplete & & OnComplete )
2022-05-31 12:42:17 -04:00
{
2022-07-18 12:23:16 -04:00
THttpUniquePtr < IHttpRequest > Request = CreateRpcRequest ( ) ;
Request - > SetContentType ( EHttpMediaType : : CbObject ) ;
Request - > SetBody ( RequestObject . GetBuffer ( ) . MakeOwned ( ) ) ;
2022-12-16 15:47:14 -05:00
new FAsyncCbPackageReceiver ( MoveTemp ( Request ) , & Owner , ZenService . GetInstance ( ) , MoveTemp ( OnComplete ) ) ;
2022-07-18 12:23:16 -04:00
}
void FZenCacheStore : : EnqueueAsyncRpc ( IRequestOwner & Owner , const FCbPackage & RequestPackage , FOnRpcComplete & & OnComplete )
{
THttpUniquePtr < IHttpRequest > Request = CreateRpcRequest ( ) ;
Request - > SetContentType ( EHttpMediaType : : CbPackage ) ;
Request - > SetBody ( SaveRpcPackage ( RequestPackage ) ) ;
2022-12-16 15:47:14 -05:00
new FAsyncCbPackageReceiver ( MoveTemp ( Request ) , & Owner , ZenService . GetInstance ( ) , MoveTemp ( OnComplete ) ) ;
2022-05-31 12:42:17 -04:00
}
2023-12-13 11:34:21 -05:00
void FZenCacheStore : : ActivatePerformanceEvaluationThread ( )
{
if ( ! PerformanceEvaluationThread . IsSet ( ) )
{
PerformanceEvaluationThread . Emplace ( TEXT ( " ZenCacheStore Performance Evaluation " ) , [ this ]
{
while ( ! PerformanceEvaluationThreadShutdownEvent . WaitFor ( FMonotonicTimeSpan : : FromSeconds ( 30.0 ) ) )
{
IRequestOwner & Owner ( PerformanceEvaluationRequestOwner ) ;
FRequestBarrier Barrier ( Owner ) ;
THttpUniquePtr < IHttpRequest > Request = RequestQueue . CreateRequest ( { } ) ;
TAnsiStringBuilder < 256 > StatusUri ;
StatusUri < < ZenService . GetInstance ( ) . GetURL ( ) < < ANSITEXTVIEW ( " /health/ready " ) ;
Request - > SetUri ( StatusUri ) ;
Request - > SetMethod ( EHttpMethod : : Get ) ;
Request - > AddAcceptType ( EHttpMediaType : : Text ) ;
new FAsyncHealthReceiver ( MoveTemp ( Request ) , & Owner , ZenService . GetInstance ( ) , [ this , StartTime = FMonotonicTimePoint : : Now ( ) ] ( THttpUniquePtr < IHttpResponse > & HttpResponse , EHealth Health )
{
if ( Health ! = EHealth : : Ok )
{
// Any non-ok health means we hold off any possibility of reactivating and we don't add the lagency to the stats
// as the failure may be client-side and instantaneous which will create an artificially low latency measurement.
return ;
}
double LatencySec = ( HttpResponse - > GetStats ( ) . StartTransferTime - HttpResponse - > GetStats ( ) . ConnectTime ) ;
StoreStats - > AddLatency ( StartTime , FMonotonicTimePoint : : Now ( ) , FMonotonicTimeSpan : : FromSeconds ( LatencySec ) ) ;
if ( ! bTryEvaluatePerformance | | ( StoreStats - > GetAverageLatency ( ) * 1000 < = DeactivateAtMs ) )
{
if ( PerformanceEvaluationThread . IsSet ( ) )
{
PerformanceEvaluationThreadShutdownEvent . Notify ( ) ;
}
if ( bDeactivatedForPerformance . load ( std : : memory_order_relaxed ) )
{
StoreOwner - > SetFlags ( this , OperationalFlags ) ;
UE_LOG ( LogDerivedDataCache , Display ,
TEXT ( " %s: Performance has improved and meets minimum performance criteria. "
" It will be reactivated now. " ) ,
* GetName ( ) ) ;
bDeactivatedForPerformance . store ( false , std : : memory_order_relaxed ) ;
UpdateStatus ( ) ;
}
}
} ) ;
}
} ) ;
}
}
2024-01-09 06:08:29 -05:00
void FZenCacheStore : : ConditionalUpdateStorageSize ( )
{
if ( ! StoreStats )
{
return ;
}
// Look for an opportunity to measure and evaluate if storage size is acceptable.
int64 LocalStorageSizeUpdateTicks = LastStorageSizeUpdateTicks . load ( std : : memory_order_relaxed ) ;
FTimespan TimespanSinceLastStorageSizeUpdate = FDateTime : : UtcNow ( ) - FDateTime ( LocalStorageSizeUpdateTicks ) ;
if ( TimespanSinceLastStorageSizeUpdate < FTimespan : : FromSeconds ( 30 ) )
{
return ;
}
if ( ! LastStorageSizeUpdateTicks . compare_exchange_strong ( LocalStorageSizeUpdateTicks , FDateTime : : UtcNow ( ) . GetTicks ( ) ) )
{
return ;
}
bool PhysicalSizeIsValid = false ;
double PhysicalSize = 0.0 ;
Zen : : FZenCacheStats ZenCacheStats ;
if ( ZenService . GetInstance ( ) . GetCacheStats ( ZenCacheStats ) )
{
PhysicalSize + = ZenCacheStats . General . Size . Disk + static_cast < double > ( ZenCacheStats . CID . Size . Total ) ;
PhysicalSizeIsValid = true ;
}
Zen : : FZenProjectStats ZenProjectStats ;
if ( ZenService . GetInstance ( ) . GetProjectStats ( ZenProjectStats ) )
{
PhysicalSize + = ZenProjectStats . General . Size . Disk ;
PhysicalSizeIsValid = true ;
}
if ( PhysicalSizeIsValid )
{
StoreStats - > SetTotalPhysicalSize ( static_cast < uint64 > ( PhysicalSize ) ) ;
}
}
2023-11-07 17:56:15 -05:00
void FZenCacheStore : : ConditionalEvaluatePerformance ( )
{
if ( ! bTryEvaluatePerformance )
{
return ;
}
// Look for an opportunity to measure and evaluate if performance is acceptable.
int64 LocalLastPerfEvaluationTicks = LastPerformanceEvaluationTicks . load ( std : : memory_order_relaxed ) ;
FTimespan TimespanSinceLastPerfEval = FDateTime : : UtcNow ( ) - FDateTime ( LocalLastPerfEvaluationTicks ) ;
if ( TimespanSinceLastPerfEval < FTimespan : : FromSeconds ( 30 ) )
{
return ;
}
if ( ! LastPerformanceEvaluationTicks . compare_exchange_strong ( LocalLastPerfEvaluationTicks , FDateTime : : UtcNow ( ) . GetTicks ( ) ) )
{
return ;
}
// We won the race and get to do the performance check
if ( PerformanceEvaluationThread . IsSet ( ) & & PerformanceEvaluationThreadShutdownEvent . IsNotified ( ) )
{
// Join and cleanup old thread before we consider whether we need to start a new one
PerformanceEvaluationThread - > Join ( ) ;
PerformanceEvaluationThread . Reset ( ) ;
PerformanceEvaluationThreadShutdownEvent . Reset ( ) ;
}
if ( StoreStats - > GetAverageLatency ( ) * 1000 > DeactivateAtMs )
{
if ( ! bDeactivatedForPerformance . load ( std : : memory_order_relaxed ) )
{
2024-03-05 11:24:22 -05:00
StoreOwner - > SetFlags ( this , OperationalFlags & ~ ( ECacheStoreFlags : : Store | ECacheStoreFlags : : Query ) ) ;
2023-12-13 11:34:21 -05:00
UE_LOG ( LogDerivedDataCache , Display ,
2023-11-07 17:56:15 -05:00
TEXT ( " %s: Performance does not meet minimum criteria. "
" It will be deactivated until performance measurements improve. "
" If this is consistent, consider disabling this cache store through "
" environment variables or other configuration. " ) ,
* GetName ( ) ) ;
bDeactivatedForPerformance . store ( true , std : : memory_order_relaxed ) ;
UpdateStatus ( ) ;
}
2023-12-13 11:34:21 -05:00
ActivatePerformanceEvaluationThread ( ) ;
2023-11-07 17:56:15 -05:00
}
}
void FZenCacheStore : : UpdateStatus ( )
{
if ( StoreStats )
{
if ( bDeactivatedForPerformance . load ( std : : memory_order_relaxed ) )
{
2023-12-13 11:34:21 -05:00
StoreStats - > SetStatus ( ECacheStoreStatusCode : : Warning , NSLOCTEXT ( " DerivedDataCache " , " DeactivatedForPerformanceOrReadiness " , " Deactivated for performance or readiness " ) ) ;
2023-11-07 17:56:15 -05:00
}
else
{
StoreStats - > SetStatus ( ECacheStoreStatusCode : : None , { } ) ;
}
}
}
2022-05-31 22:01:53 -04:00
void FZenCacheStore : : LegacyStats ( FDerivedDataCacheStatsNode & OutNode )
2022-05-30 18:14:02 -04:00
{
2023-06-13 17:14:59 -04:00
checkNoEntry ( ) ;
2022-05-30 18:14:02 -04:00
}
2022-05-31 22:01:53 -04:00
bool FZenCacheStore : : LegacyDebugOptions ( FBackendDebugOptions & InOptions )
2022-05-30 18:14:02 -04:00
{
DebugOptions = InOptions ;
return true ;
}
void FZenCacheStore : : Put (
const TConstArrayView < FCachePutRequest > Requests ,
IRequestOwner & Owner ,
FOnCachePutComplete & & OnComplete )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ZenDDC : : PutCachedRecord ) ;
2022-06-10 12:56:08 -04:00
TRefCountPtr < FPutOp > PutOp = MakeAsyncOp < FPutOp > ( * this , Owner , Requests , MoveTemp ( OnComplete ) ) ;
PutOp - > IssueRequests ( ) ;
2022-05-30 18:14:02 -04:00
}
void FZenCacheStore : : Get (
const TConstArrayView < FCacheGetRequest > Requests ,
IRequestOwner & Owner ,
FOnCacheGetComplete & & OnComplete )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ZenDDC : : GetCacheRecord ) ;
2022-06-10 12:56:08 -04:00
TRefCountPtr < FGetOp > GetOp = MakeAsyncOp < FGetOp > ( * this , Owner , Requests , MoveTemp ( OnComplete ) ) ;
GetOp - > IssueRequests ( ) ;
2022-05-30 18:14:02 -04:00
}
void FZenCacheStore : : PutValue (
TConstArrayView < FCachePutValueRequest > Requests ,
IRequestOwner & Owner ,
FOnCachePutValueComplete & & OnComplete )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ZenDDC : : PutValue ) ;
2022-06-10 12:56:08 -04:00
TRefCountPtr < FPutValueOp > PutValueOp = MakeAsyncOp < FPutValueOp > ( * this , Owner , Requests , MoveTemp ( OnComplete ) ) ;
PutValueOp - > IssueRequests ( ) ;
2022-05-30 18:14:02 -04:00
}
void FZenCacheStore : : GetValue (
TConstArrayView < FCacheGetValueRequest > Requests ,
IRequestOwner & Owner ,
FOnCacheGetValueComplete & & OnComplete )
2022-06-10 12:56:08 -04:00
{
2022-05-30 18:14:02 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( ZenDDC : : GetValue ) ;
2022-06-10 12:56:08 -04:00
TRefCountPtr < FGetValueOp > GetValueOp = MakeAsyncOp < FGetValueOp > ( * this , Owner , Requests , MoveTemp ( OnComplete ) ) ;
GetValueOp - > IssueRequests ( ) ;
2022-05-30 18:14:02 -04:00
}
void FZenCacheStore : : GetChunks (
TConstArrayView < FCacheGetChunkRequest > Requests ,
IRequestOwner & Owner ,
FOnCacheGetChunkComplete & & OnComplete )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ZenDDC : : GetChunks ) ;
2022-06-10 12:56:08 -04:00
TRefCountPtr < FGetChunksOp > GetChunksOp = MakeAsyncOp < FGetChunksOp > ( * this , Owner , Requests , MoveTemp ( OnComplete ) ) ;
GetChunksOp - > IssueRequests ( ) ;
2022-05-30 18:14:02 -04:00
}
2023-11-25 16:22:26 -05:00
void FZenCacheStoreParams : : Parse ( const TCHAR * NodeName , const TCHAR * Config )
2022-05-30 18:14:02 -04:00
{
2023-11-25 16:22:26 -05:00
Name = NodeName ;
if ( FString ServerId ; FParse : : Value ( Config , TEXT ( " ServerID= " ) , ServerId ) )
{
FString ServerEntry ;
const TCHAR * ServerSection = TEXT ( " StorageServers " ) ;
if ( GConfig - > GetString ( ServerSection , * ServerId , ServerEntry , GEngineIni ) )
{
Parse ( NodeName , * ServerEntry ) ;
}
else
{
UE_LOG ( LogDerivedDataCache , Warning , TEXT ( " %s: Using ServerID=%s which was not found in [%s] " ) , NodeName , * ServerId , ServerSection ) ;
}
}
FParse : : Value ( Config , TEXT ( " Host= " ) , Host ) ;
2022-05-31 22:01:53 -04:00
2023-01-23 12:48:38 -05:00
FString OverrideName ;
if ( FParse : : Value ( Config , TEXT ( " EnvHostOverride= " ) , OverrideName ) )
{
2023-11-25 16:22:26 -05:00
FString HostEnv = FPlatformMisc : : GetEnvironmentVariable ( * OverrideName ) ;
if ( ! HostEnv . IsEmpty ( ) )
2023-01-23 12:48:38 -05:00
{
2023-11-25 16:22:26 -05:00
Host = HostEnv ;
UE_LOG ( LogDerivedDataCache , Log , TEXT ( " %s: Found environment override for Host %s=%s " ) , NodeName , * OverrideName , * Host ) ;
2023-01-23 12:48:38 -05:00
}
}
if ( FParse : : Value ( Config , TEXT ( " CommandLineHostOverride= " ) , OverrideName ) )
{
2023-11-25 16:22:26 -05:00
if ( FParse : : Value ( FCommandLine : : Get ( ) , * ( OverrideName + TEXT ( " = " ) ) , Host ) )
2023-01-23 12:48:38 -05:00
{
2023-11-25 16:22:26 -05:00
UE_LOG ( LogDerivedDataCache , Log , TEXT ( " %s: Found command line override for Host %s=%s " ) , NodeName , * OverrideName , * Host ) ;
2023-01-23 12:48:38 -05:00
}
}
2023-11-25 16:22:26 -05:00
FParse : : Value ( Config , TEXT ( " Namespace= " ) , Namespace ) ;
FParse : : Value ( Config , TEXT ( " StructuredNamespace= " ) , Namespace ) ;
FParse : : Bool ( Config , TEXT ( " ReadOnly= " ) , bReadOnly ) ;
// Sandbox and flush configuration for use in Cold/Warm type use cases
FParse : : Value ( Config , TEXT ( " Sandbox= " ) , Sandbox ) ;
FParse : : Bool ( Config , TEXT ( " Flush= " ) , bFlush ) ;
// Performance deactivation
FParse : : Value ( Config , TEXT ( " DeactivateAt= " ) , DeactivateAtMs ) ;
// Explicit local and remote configuration
if ( bool bExplicitLocal = false ; FParse : : Bool ( Config , TEXT ( " Local= " ) , bExplicitLocal ) )
2023-01-23 12:48:38 -05:00
{
2023-11-25 16:22:26 -05:00
bLocal = bExplicitLocal ;
}
if ( bool bExplicitRemote = false ; FParse : : Bool ( Config , TEXT ( " Remote= " ) , bExplicitRemote ) )
{
bRemote = bExplicitRemote ;
}
// Request batch fracturing configuration
FParse : : Value ( Config , TEXT ( " MaxBatchPutKB= " ) , MaxBatchPutKB ) ;
FParse : : Value ( Config , TEXT ( " RecordBatchSize= " ) , RecordBatchSize ) ;
FParse : : Value ( Config , TEXT ( " ChunksBatchSize= " ) , ChunksBatchSize ) ;
}
ILegacyCacheStore * CreateZenCacheStore ( const TCHAR * NodeName , const TCHAR * Config , ICacheStoreOwner * Owner )
{
FZenCacheStoreParams Params ;
Params . Parse ( NodeName , Config ) ;
if ( Params . Host = = TEXTVIEW ( " None " ) )
{
UE_LOG ( LogDerivedDataCache , Log , TEXT ( " %s: Disabled because Host is set to 'None' " ) , NodeName ) ;
2023-06-13 17:14:59 -04:00
return nullptr ;
2023-01-23 12:48:38 -05:00
}
2023-11-25 16:22:26 -05:00
if ( Params . Namespace . IsEmpty ( ) )
2022-05-30 18:14:02 -04:00
{
2023-11-25 16:22:26 -05:00
Params . Namespace = FApp : : GetProjectName ( ) ;
UE_LOG ( LogDerivedDataCache , Warning , TEXT ( " %s: Missing required parameter 'Namespace', falling back to '%s' " ) , NodeName , * Params . Namespace ) ;
2022-05-30 18:14:02 -04:00
}
2022-05-31 22:01:53 -04:00
2023-11-25 16:22:26 -05:00
bool bHasSandbox = ! Params . Sandbox . IsEmpty ( ) ;
2023-01-11 20:57:13 -05:00
bool bUseLocalDataCachePathOverrides = ! bHasSandbox ;
2022-12-14 15:06:30 -05:00
FString CachePathOverride ;
2023-11-25 16:22:26 -05:00
if ( bUseLocalDataCachePathOverrides & & UE : : Zen : : Private : : IsLocalAutoLaunched ( Params . Host ) & & UE : : Zen : : Private : : GetLocalDataCachePathOverride ( CachePathOverride ) )
2022-12-14 15:06:30 -05:00
{
if ( CachePathOverride = = TEXT ( " None " ) )
{
2023-11-25 16:22:26 -05:00
UE_LOG ( LogDerivedDataCache , Log , TEXT ( " %s: Disabled because path is set to 'None' " ) , NodeName ) ;
2023-06-13 17:14:59 -04:00
return nullptr ;
2022-12-14 15:06:30 -05:00
}
}
2023-01-03 15:58:30 -05:00
TUniquePtr < FZenCacheStore > Backend ;
2023-01-11 20:57:13 -05:00
if ( bHasSandbox )
2023-01-03 15:58:30 -05:00
{
Zen : : FServiceSettings DefaultServiceSettings ;
DefaultServiceSettings . ReadFromConfig ( ) ;
if ( ! DefaultServiceSettings . IsAutoLaunch ( ) )
{
2023-12-04 18:28:00 -05:00
UE_LOG ( LogDerivedDataCache , Warning , TEXT ( " %s: Attempting to use a sandbox when there is no default autolaunch configured to inherit settings from. Cache will be disabled. " ) , NodeName ) ;
2023-06-13 17:14:59 -04:00
return nullptr ;
2023-01-03 15:58:30 -05:00
}
// Make a unique local instance (not the default local instance) of ZenServer
Zen : : FServiceSettings ServiceSettings ;
ServiceSettings . SettingsVariant . Emplace < Zen : : FServiceAutoLaunchSettings > ( ) ;
Zen : : FServiceAutoLaunchSettings & AutoLaunchSettings = ServiceSettings . SettingsVariant . Get < Zen : : FServiceAutoLaunchSettings > ( ) ;
const Zen : : FServiceAutoLaunchSettings & DefaultAutoLaunchSettings = DefaultServiceSettings . SettingsVariant . Get < Zen : : FServiceAutoLaunchSettings > ( ) ;
AutoLaunchSettings = DefaultAutoLaunchSettings ;
// Default as one more than the default port to not collide. Multiple sandboxes will share a desired port, but will get differing effective ports.
AutoLaunchSettings . DesiredPort + + ;
FPaths : : NormalizeDirectoryName ( AutoLaunchSettings . DataPath ) ;
AutoLaunchSettings . DataPath + = TEXT ( " _ " ) ;
2023-11-25 16:22:26 -05:00
AutoLaunchSettings . DataPath + = Params . Sandbox ;
2023-06-23 00:49:34 -04:00
AutoLaunchSettings . bIsDefaultSharedRunContext = false ;
2023-01-03 15:58:30 -05:00
// The unique local instances will always limit process lifetime for now to avoid accumulating many of them
AutoLaunchSettings . bLimitProcessLifetime = true ;
// Flush the cache if requested.
2023-10-19 18:18:01 -04:00
uint32 MultiprocessId = UE : : GetMultiprocessId ( ) ;
2023-11-25 16:22:26 -05:00
if ( Params . bFlush & & ( MultiprocessId = = 0 ) )
2023-01-03 15:58:30 -05:00
{
bool bStopped = true ;
if ( UE : : Zen : : IsLocalServiceRunning ( * AutoLaunchSettings . DataPath ) )
{
bStopped = UE : : Zen : : StopLocalService ( * AutoLaunchSettings . DataPath ) ;
}
if ( bStopped )
{
IFileManager : : Get ( ) . DeleteDirectory ( * ( AutoLaunchSettings . DataPath / TEXT ( " " ) ) , /*bRequireExists*/ false , /*bTree*/ true ) ;
}
else
{
UE_LOG ( LogDerivedDataCache , Warning , TEXT ( " %s: Zen DDC could not be flushed due to an existing instance not shutting down when requested. " ) , NodeName ) ;
}
}
2023-11-25 16:22:26 -05:00
Backend = MakeUnique < FZenCacheStore > ( MoveTemp ( ServiceSettings ) , Params , Owner ) ;
2023-01-03 15:58:30 -05:00
}
else
{
2023-11-25 16:22:26 -05:00
Backend = MakeUnique < FZenCacheStore > ( Params , Owner ) ;
2023-01-03 15:58:30 -05:00
}
2022-05-31 22:01:53 -04:00
if ( ! Backend - > IsUsable ( ) )
{
2023-11-15 17:17:29 -05:00
if ( Backend - > IsLocalConnection ( ) )
{
UE_LOG ( LogDerivedDataCache , Warning , TEXT ( " %s: Failed to contact the service (%s), will not use it. " ) , NodeName , * Backend - > GetName ( ) ) ;
}
else
{
UE_LOG ( LogDerivedDataCache , Display , TEXT ( " %s: Failed to contact the service (%s), will not use it. " ) , NodeName , * Backend - > GetName ( ) ) ;
}
2022-05-31 22:01:53 -04:00
Backend . Reset ( ) ;
2023-06-13 17:14:59 -04:00
return nullptr ;
2022-05-31 22:01:53 -04:00
}
2023-06-13 17:14:59 -04:00
return Backend . Release ( ) ;
2022-05-30 18:14:02 -04:00
}
} // namespace UE::DerivedData
# else
namespace UE : : DerivedData
{
2023-06-13 17:14:59 -04:00
ILegacyCacheStore * CreateZenCacheStore ( const TCHAR * NodeName , const TCHAR * Config , ICacheStoreOwner * Owner )
2022-05-30 18:14:02 -04:00
{
2022-05-31 22:01:53 -04:00
UE_LOG ( LogDerivedDataCache , Warning , TEXT ( " %s: Zen cache is not yet supported in the current build configuration. " ) , NodeName ) ;
2023-06-13 17:14:59 -04:00
return nullptr ;
2022-05-30 18:14:02 -04:00
}
} // UE::DerivedData
2022-02-02 05:33:16 -05:00
# endif // UE_WITH_ZEN