2021-06-24 00:51:58 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2022-05-19 21:10:57 -04:00
# include "BulkDataRegistryImpl.h"
2021-06-24 00:51:58 -04:00
# include "Serialization/BulkDataRegistry.h"
# include "Compression/CompressedBuffer.h"
2021-08-05 13:12:08 -04:00
# include "DerivedDataCache.h"
2021-06-24 00:51:58 -04:00
# include "DerivedDataCacheRecord.h"
# include "EditorBuildInputResolver.h"
# include "EditorDomain/EditorDomainUtils.h"
# include "HAL/PlatformTime.h"
# include "Interfaces/IPluginManager.h"
# include "IO/IoHash.h"
# include "Memory/SharedBuffer.h"
# include "Misc/CoreDelegates.h"
# include "Misc/ScopeLock.h"
# include "Misc/ScopeRWLock.h"
# include "Serialization/MemoryReader.h"
# include "Templates/RefCounting.h"
# include "TickableEditorObject.h"
# include "UObject/Package.h"
2021-07-15 09:57:13 -04:00
# include "UObject/UObjectGlobals.h"
2021-06-24 00:51:58 -04:00
# include "UObject/UObjectIterator.h"
namespace UE : : BulkDataRegistry : : Private
{
namespace Constants
{
constexpr uint64 TempLoadedPayloadsSizeBudget = 1024 * 1024 * 100 ;
constexpr double TempLoadedPayloadsDuration = 60. ;
2021-07-15 09:57:13 -04:00
}
2021-06-24 00:51:58 -04:00
2021-07-15 09:57:13 -04:00
TConstArrayView < uint8 > MakeArrayView ( FSharedBuffer Buffer )
{
return TConstArrayView < uint8 > ( reinterpret_cast < const uint8 * > ( Buffer . GetData ( ) ) , Buffer . GetSize ( ) ) ;
2021-06-24 00:51:58 -04:00
}
/** Add a hook to the BulkDataRegistry's startup delegate to use the EditorDomain as the BulkDataRegistry */
class FEditorDomainRegisterAsBulkDataRegistry
{
public :
FEditorDomainRegisterAsBulkDataRegistry ( )
{
IBulkDataRegistry : : GetSetBulkDataRegistryDelegate ( ) . BindStatic ( SetBulkDataRegistry ) ;
}
static IBulkDataRegistry * SetBulkDataRegistry ( )
{
2022-05-19 21:10:57 -04:00
return new FBulkDataRegistryImpl ( ) ;
2021-06-24 00:51:58 -04:00
}
} GRegisterAsBulkDataRegistry ;
2022-05-19 21:10:57 -04:00
FBulkDataRegistryImpl : : FBulkDataRegistryImpl ( )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
SharedDataLock = new FTaskSharedDataLock ( ) ;
2021-06-24 00:51:58 -04:00
// We piggyback on the BulkDataRegistry hook to set the pointer to tunnel in the pointer to the EditorBuildInputResolver as well
SetGlobalBuildInputResolver ( & UE : : DerivedData : : FEditorBuildInputResolver : : Get ( ) ) ;
2022-05-19 21:10:57 -04:00
FCoreUObjectDelegates : : OnEndLoadPackage . AddRaw ( this , & FBulkDataRegistryImpl : : OnEndLoadPackage ) ;
2021-06-24 00:51:58 -04:00
}
2022-05-19 21:10:57 -04:00
FBulkDataRegistryImpl : : ~ FBulkDataRegistryImpl ( )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:49:49 -04:00
FCoreUObjectDelegates : : OnEndLoadPackage . RemoveAll ( this ) ;
2021-06-24 00:51:58 -04:00
SetGlobalBuildInputResolver ( nullptr ) ;
2021-07-12 07:59:52 -04:00
TMap < FGuid , FUpdatingPayload > LocalUpdatingPayloads ;
{
FWriteScopeLock SharedDataScopeLock ( SharedDataLock - > ActiveLock ) ;
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
FScopeLock PendingPackageScopeLock ( & PendingPackageLock ) ;
// Disable all activity that might come in from other threads
bActive = false ;
SharedDataLock - > bActive = false ;
// Take custody of UpdatingPayloads
Swap ( LocalUpdatingPayloads , UpdatingPayloads ) ;
}
2021-07-15 09:57:13 -04:00
// Since the UpdatingPayloads AsyncTasks can no longer access their Requesters, we have to call those callbacks
2021-07-12 07:59:52 -04:00
for ( TPair < FGuid , FUpdatingPayload > & Pair : LocalUpdatingPayloads )
{
for ( TUniqueFunction < void ( bool , const FCompressedBuffer & ) > & Requester : Pair . Value . Requesters )
{
Requester ( false , FCompressedBuffer ( ) ) ;
}
}
LocalUpdatingPayloads . Empty ( ) ;
// Clear PendingPackages
2021-07-15 09:57:13 -04:00
TMap < FName , TUniquePtr < FPendingPackage > > LocalPendingPackages ;
2021-06-24 00:51:58 -04:00
{
FScopeLock PendingPackageScopeLock ( & PendingPackageLock ) ;
2021-07-15 09:57:13 -04:00
// Take custody of PendingPackages
Swap ( LocalPendingPackages , PendingPackages ) ;
}
for ( TPair < FName , TUniquePtr < FPendingPackage > > & PendingPackagePair : LocalPendingPackages )
{
PendingPackagePair . Value - > Cancel ( ) ;
}
LocalPendingPackages . Empty ( ) ;
// Clear PendingPackagePayloadIds. We have to take custody of PendingPayloadIds after calling
// Cancel from all FPendingPackage, as the FPendingPackages have callbacks that may write to PendingPayloadIds
TMap < FGuid , TRefCountPtr < FPendingPayloadId > > LocalPendingPayloadIds ;
{
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
// Take custody of PendingPayloadIds
Swap ( LocalPendingPayloadIds , PendingPayloadIds ) ;
}
for ( TPair < FGuid , TRefCountPtr < FPendingPayloadId > > & PendingPayloadIdPair : LocalPendingPayloadIds )
{
PendingPayloadIdPair . Value - > Cancel ( ) ;
}
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : OnEndLoadPackage ( const FEndLoadPackageContext & Context )
2021-07-15 09:57:13 -04:00
{
TArray < TUniquePtr < FPendingPackage > > PackagesToWrite ;
{
2021-08-09 07:36:56 -04:00
FScopeLock PendingPackageScopeLock ( & PendingPackageLock ) ;
2022-02-17 22:02:59 -05:00
for ( UPackage * LoadedPackage : Context . LoadedPackages )
2021-07-15 09:57:13 -04:00
{
2021-08-09 07:36:56 -04:00
FName PackageName = LoadedPackage - > GetFName ( ) ;
uint32 KeyHash = GetTypeHash ( PackageName ) ;
TUniquePtr < FPendingPackage > * PendingPackage = PendingPackages . FindByHash ( KeyHash , PackageName ) ;
if ( PendingPackage )
2021-07-15 09:57:13 -04:00
{
2021-08-09 07:36:56 -04:00
bool bShouldRemove ;
bool bShouldWriteCache ;
check ( PendingPackage - > IsValid ( ) ) ;
( * PendingPackage ) - > OnEndLoad ( bShouldRemove , bShouldWriteCache ) ;
// We do not hold a lock when calling WriteCache, so we require that the package no longer
// be accessible to other threads through PendingPackages if we need to write the cache,
// so bShouldRemove must be true if bShouldWriteCache is
check ( ! bShouldWriteCache | | bShouldRemove ) ;
if ( bShouldRemove )
{
if ( bShouldWriteCache )
{
PackagesToWrite . Add ( MoveTemp ( * PendingPackage ) ) ;
}
PendingPackages . RemoveByHash ( KeyHash , PackageName ) ;
}
2021-07-15 09:57:13 -04:00
}
}
}
for ( TUniquePtr < FPendingPackage > & Package : PackagesToWrite )
{
Package - > WriteCache ( ) ;
2021-06-24 00:51:58 -04:00
}
}
2022-04-21 12:03:36 -04:00
UE : : BulkDataRegistry : : ERegisterResult
2022-05-19 21:10:57 -04:00
FBulkDataRegistryImpl : : TryRegister ( UPackage * Owner , const UE : : Serialization : : FEditorBulkData & BulkData )
2021-06-24 00:51:58 -04:00
{
if ( ! BulkData . GetIdentifier ( ) . IsValid ( ) )
{
2022-04-21 12:03:36 -04:00
return UE : : BulkDataRegistry : : ERegisterResult : : Success ;
2021-06-24 00:51:58 -04:00
}
2022-04-21 12:03:36 -04:00
bool bAllowedToReadWritePayloadIdFromCache = false ;
FName PackageName ;
2022-01-21 09:18:53 -05:00
UE : : Serialization : : FEditorBulkData CopyBulk ( BulkData . CopyTornOff ( ) ) ;
2022-04-21 12:03:36 -04:00
UE : : Serialization : : FEditorBulkData PendingPackageBulk ;
if ( Owner )
2021-06-24 00:51:58 -04:00
{
PackageName = Owner - > GetFName ( ) ;
2022-04-21 12:03:36 -04:00
if ( Owner - > GetFileSize ( ) // We only cache the BulkDataList for disk packages
& & ! Owner - > GetHasBeenEndLoaded ( ) // We only cache BulkDatas that are loaded before the package finishes loading
& & CopyBulk . CanSaveForRegistry ( )
)
{
bAllowedToReadWritePayloadIdFromCache = true ;
PendingPackageBulk = CopyBulk ;
}
2021-06-24 00:51:58 -04:00
}
2022-01-03 17:56:37 -05:00
{
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
check ( bActive ) ; // Registrations should not come in after we destruct
2022-04-21 12:03:36 -04:00
UE : : BulkDataRegistry : : Private : : FRegisteredBulk & RegisteredBulk = Registry . FindOrAdd ( BulkData . GetIdentifier ( ) ) ;
if ( RegisteredBulk . bRegistered )
{
bool bAllowSharing = false ;
// If the original BulkData has left memory and a new bulkdata registers with the same package owner,
// assume that it is the same BulkData being reloaded and allow the sharing
bAllowSharing | = ( ! RegisteredBulk . bInMemory & & PackageName = = RegisteredBulk . PackageName ) ;
if ( ! bAllowSharing )
{
return UE : : BulkDataRegistry : : ERegisterResult : : AlreadyExists ;
}
if ( RegisteredBulk . PackageName . IsNone ( ) )
{
RegisteredBulk . PackageName = PackageName ;
}
RegisteredBulk . bRegistered = true ;
RegisteredBulk . bInMemory = true ;
RegisteredBulk . bAllowedToWritePayloadIdToCache = false ;
RegisteredBulk . bPayloadAvailable = true ;
// For updated registrations, skip reading payloadid from cache, and call ResaveSizeTracker.Update rather than Register.
ResaveSizeTracker . UpdateRegistrationData ( Owner , BulkData ) ;
return UE : : BulkDataRegistry : : ERegisterResult : : Success ;
}
else
{
bool bCachedLocationMatches = false ;
UE : : Serialization : : FEditorBulkData & TargetBulkData = RegisteredBulk . BulkData ;
if ( TargetBulkData . GetIdentifier ( ) . IsValid ( ) )
{
// This BulkData was added when loading the cached list of BulkData for the package, but has not been registered by an in-memory bulkdata
check ( TargetBulkData . GetIdentifier ( ) = = BulkData . GetIdentifier ( ) ) ;
bCachedLocationMatches = BulkData . LocationMatches ( TargetBulkData ) ;
}
if ( ! bCachedLocationMatches | | ! BulkData . HasPlaceholderPayloadId ( ) | | TargetBulkData . HasPlaceholderPayloadId ( ) )
{
// Copy the new BulkData over the value we got from the cache; the new BulkData is more authoritative
TargetBulkData = MoveTemp ( CopyBulk ) ;
RegisteredBulk . bAllowedToWritePayloadIdToCache = bAllowedToReadWritePayloadIdFromCache ;
}
else
{
// Otherwise Keep the TargetBulkData, since it matches the location and has already calculated the PayloadId
RegisteredBulk . bAllowedToWritePayloadIdToCache = false ;
}
RegisteredBulk . PackageName = PackageName ;
RegisteredBulk . bRegistered = true ;
RegisteredBulk . bInMemory = true ;
RegisteredBulk . bPayloadAvailable = true ;
}
}
if ( bAllowedToReadWritePayloadIdFromCache )
{
AddPendingPackageBulkData ( PackageName , MoveTemp ( PendingPackageBulk ) ) ;
2022-01-03 17:56:37 -05:00
}
ResaveSizeTracker . Register ( Owner , BulkData ) ;
2022-04-21 12:03:36 -04:00
return UE : : BulkDataRegistry : : ERegisterResult : : Success ;
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : UpdateRegistrationData ( UPackage * Owner , const UE : : Serialization : : FEditorBulkData & BulkData )
2022-04-21 12:03:36 -04:00
{
if ( ! BulkData . GetIdentifier ( ) . IsValid ( ) )
{
UE_LOG ( LogBulkDataRegistry , Warning , TEXT ( " UpdateRegistrationData called with invalid BulkData for Owner %s. " ) ,
Owner ? * Owner - > GetName ( ) : TEXT ( " <unknown> " ) ) ;
return ;
}
FName PackageName = Owner ? Owner - > GetFName ( ) : NAME_None ;
{
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
check ( bActive ) ; // Registrations should not come in after we destruct
UE : : BulkDataRegistry : : Private : : FRegisteredBulk & RegisteredBulk = Registry . FindOrAdd ( BulkData . GetIdentifier ( ) ) ;
// Add the owner if we previously did not have an owner, otherwise keep the first owner
if ( RegisteredBulk . PackageName . IsNone ( ) )
{
RegisteredBulk . PackageName = PackageName ;
}
RegisteredBulk . BulkData = BulkData . CopyTornOff ( ) ;
RegisteredBulk . bAllowedToWritePayloadIdToCache = false ;
RegisteredBulk . bRegistered = true ;
RegisteredBulk . bInMemory = true ;
RegisteredBulk . bPayloadAvailable = true ;
}
ResaveSizeTracker . UpdateRegistrationData ( Owner , BulkData ) ;
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : Unregister ( const UE : : Serialization : : FEditorBulkData & BulkData )
2022-04-21 12:03:36 -04:00
{
const FGuid & Key = BulkData . GetIdentifier ( ) ;
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
check ( bActive ) ; // Deregistrations should not come in after we destruct
Registry . Remove ( Key ) ;
2021-07-15 09:49:49 -04:00
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : OnExitMemory ( const UE : : Serialization : : FEditorBulkData & BulkData )
2021-06-24 00:51:58 -04:00
{
const FGuid & Key = BulkData . GetIdentifier ( ) ;
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
2021-07-12 07:59:52 -04:00
check ( bActive ) ; // Deregistrations should not come in after we destruct
FRegisteredBulk * Existing = Registry . Find ( Key ) ;
2021-06-24 00:51:58 -04:00
if ( Existing )
{
if ( Existing - > BulkData . IsMemoryOnlyPayload ( ) )
{
2022-04-21 12:03:36 -04:00
Existing - > BulkData . Reset ( ) ;
Existing - > BulkData . TearOff ( ) ; // Keep the TearOff flag after resetting
Existing - > bPayloadAvailable = false ;
2021-06-24 00:51:58 -04:00
}
2022-04-21 12:03:36 -04:00
Existing - > bInMemory = false ;
2021-06-24 00:51:58 -04:00
}
}
2022-05-19 21:10:57 -04:00
TFuture < UE : : BulkDataRegistry : : FMetaData > FBulkDataRegistryImpl : : GetMeta ( const FGuid & BulkDataId )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
bool bIsWriteLock = false ;
FRWScopeLock RegistryScopeLock ( RegistryLock , SLT_ReadOnly ) ;
for ( ; ; )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
FRegisteredBulk * Existing = nullptr ;
if ( bActive )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
Existing = Registry . Find ( BulkDataId ) ;
2021-06-24 00:51:58 -04:00
}
2022-04-21 12:03:36 -04:00
if ( ! Existing | | ! Existing - > bPayloadAvailable )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
TPromise < UE : : BulkDataRegistry : : FMetaData > Promise ;
2022-04-26 12:47:22 -04:00
Promise . SetValue ( UE : : BulkDataRegistry : : FMetaData { FIoHash ( ) , 0 } ) ;
2021-06-24 00:51:58 -04:00
return Promise . GetFuture ( ) ;
}
2022-01-21 09:18:53 -05:00
UE : : Serialization : : FEditorBulkData & BulkData = Existing - > BulkData ;
2021-07-12 07:59:52 -04:00
if ( ! BulkData . HasPlaceholderPayloadId ( ) )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
TPromise < UE : : BulkDataRegistry : : FMetaData > Promise ;
2022-04-26 12:47:22 -04:00
Promise . SetValue ( UE : : BulkDataRegistry : : FMetaData { BulkData . GetPayloadId ( ) , static_cast < uint64 > ( BulkData . GetPayloadSize ( ) ) } ) ;
2021-06-24 00:51:58 -04:00
return Promise . GetFuture ( ) ;
}
2021-07-12 07:59:52 -04:00
if ( ! bIsWriteLock )
{
bIsWriteLock = true ;
RegistryScopeLock . ReleaseReadOnlyLockAndAcquireWriteLock_USE_WITH_CAUTION ( ) ;
continue ;
}
2021-06-24 00:51:58 -04:00
2021-07-12 07:59:52 -04:00
// The payload in the registry is missing its RawHash; start a thread to calculate it and subscribe our caller to the results
FUpdatingPayload & UpdatingPayload = UpdatingPayloads . FindOrAdd ( BulkDataId ) ;
if ( ! UpdatingPayload . AsyncTask )
{
UpdatingPayload . AsyncTask = new FAutoDeleteAsyncTask < FUpdatePayloadWorker > ( this , BulkData ) ;
UpdatingPayload . AsyncTask - > StartBackgroundTask ( ) ;
}
TPromise < UE : : BulkDataRegistry : : FMetaData > Promise ;
TFuture < UE : : BulkDataRegistry : : FMetaData > Future = Promise . GetFuture ( ) ;
UpdatingPayload . Requesters . Add ( [ Promise = MoveTemp ( Promise ) ] ( bool bValid , const FCompressedBuffer & Buffer ) mutable
{
2022-04-26 12:47:22 -04:00
Promise . SetValue ( UE : : BulkDataRegistry : : FMetaData { Buffer . GetRawHash ( ) , Buffer . GetRawSize ( ) } ) ;
2021-07-12 07:59:52 -04:00
} ) ;
return Future ;
2021-06-24 00:51:58 -04:00
}
}
2022-05-19 21:10:57 -04:00
TFuture < UE : : BulkDataRegistry : : FData > FBulkDataRegistryImpl : : GetData ( const FGuid & BulkDataId )
2021-06-24 00:51:58 -04:00
{
2022-01-21 09:18:53 -05:00
TOptional < UE : : Serialization : : FEditorBulkData > CopyBulk ;
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
bool bIsWriteLock = false ;
FRWScopeLock RegistryScopeLock ( RegistryLock , SLT_ReadOnly ) ;
for ( ; ; )
2021-06-24 00:51:58 -04:00
{
2021-07-12 07:59:52 -04:00
FRegisteredBulk * Existing = nullptr ;
if ( bActive )
{
Existing = Registry . Find ( BulkDataId ) ;
}
2022-04-21 12:03:36 -04:00
if ( ! Existing | | ! Existing - > bPayloadAvailable )
2021-07-12 07:59:52 -04:00
{
TPromise < UE : : BulkDataRegistry : : FData > Result ;
2022-04-26 12:47:22 -04:00
Result . SetValue ( UE : : BulkDataRegistry : : FData { FCompressedBuffer ( ) } ) ;
2021-07-12 07:59:52 -04:00
return Result . GetFuture ( ) ;
}
2021-06-24 00:51:58 -04:00
2021-07-12 07:59:52 -04:00
if ( ! Existing - > BulkData . HasPlaceholderPayloadId ( ) & & ! Existing - > bHasTempPayload )
{
2022-01-21 09:18:53 -05:00
// The contract of FEditorBulkData does not guarantee that GetCompressedPayload() is a quick operation (it may load the data
2021-07-12 07:59:52 -04:00
// synchronously), so copy the BulkData into a temporary and call it outside the lock
CopyBulk . Emplace ( Existing - > BulkData ) ;
break ;
}
2021-06-24 00:51:58 -04:00
2021-07-12 07:59:52 -04:00
if ( ! bIsWriteLock )
{
bIsWriteLock = true ;
RegistryScopeLock . ReleaseReadOnlyLockAndAcquireWriteLock_USE_WITH_CAUTION ( ) ;
continue ;
}
if ( ! Existing - > BulkData . HasPlaceholderPayloadId ( ) )
{
check ( Existing - > bHasTempPayload ) ;
// We are the first GetData call after the BulkData previously loaded its Payload to calculate the RawHash.
// Sidenote, this means GetCompressedPayload will be fast.
// But we also have the responsibility to dump the data from memory since we have now consumed it.
// Make sure we copy the data pointer before dumping it from the Registry version!
CopyBulk . Emplace ( Existing - > BulkData ) ;
Existing - > BulkData . UnloadData ( ) ;
Existing - > bHasTempPayload = false ;
break ;
}
// The payload in the registry is missing its RawHash, and we calculate that on demand whenever the data is requested,
// which is now. Instead of only returning the data to our caller, we load the data and use it to update the RawHash
// in the registry and then return the data to our caller.
FUpdatingPayload & UpdatingPayload = UpdatingPayloads . FindOrAdd ( BulkDataId ) ;
if ( ! UpdatingPayload . AsyncTask )
{
UpdatingPayload . AsyncTask = new FAutoDeleteAsyncTask < FUpdatePayloadWorker > ( this , Existing - > BulkData ) ;
}
TPromise < UE : : BulkDataRegistry : : FData > Promise ;
TFuture < UE : : BulkDataRegistry : : FData > Future = Promise . GetFuture ( ) ;
UpdatingPayload . Requesters . Add ( [ Promise = MoveTemp ( Promise ) ] ( bool bValid , const FCompressedBuffer & Buffer ) mutable
{
2022-04-26 12:47:22 -04:00
Promise . SetValue ( UE : : BulkDataRegistry : : FData { Buffer } ) ;
2021-07-12 07:59:52 -04:00
} ) ;
return Future ;
2021-06-24 00:51:58 -04:00
}
}
2021-07-12 07:59:52 -04:00
// We are calling a function that returns a TFuture on the stack-local CopyBulk, which would cause a read-after-free if the asynchronous TFuture could
2022-01-21 09:18:53 -05:00
// read from the BulkData. However, the contract of FEditorBulkData guarantees that the TFuture gets a copy of all data it needs and
2021-07-12 07:59:52 -04:00
// does not read from the BulkData after returning from GetCompressedPayload, so a read-after-free is not possible.
return CopyBulk - > GetCompressedPayload ( ) . Next ( [ ] ( FCompressedBuffer Payload )
{
2022-04-26 12:47:22 -04:00
return UE : : BulkDataRegistry : : FData { Payload } ;
2021-07-12 07:59:52 -04:00
} ) ;
2021-06-24 00:51:58 -04:00
}
2022-05-19 21:10:57 -04:00
bool FBulkDataRegistryImpl : : TryGetBulkData ( const FGuid & BulkDataId , UE : : Serialization : : FEditorBulkData * OutBulk ,
2022-04-21 12:03:36 -04:00
FName * OutOwner )
{
FReadScopeLock RegistryScopeLock ( RegistryLock ) ;
FRegisteredBulk * Existing = nullptr ;
if ( bActive )
{
Existing = Registry . Find ( BulkDataId ) ;
}
if ( Existing )
{
if ( OutBulk )
{
* OutBulk = Existing - > BulkData ;
}
if ( OutOwner )
{
* OutOwner = Existing - > PackageName ;
}
return true ;
}
return false ;
}
2022-05-19 21:10:57 -04:00
uint64 FBulkDataRegistryImpl : : GetBulkDataResaveSize ( FName PackageName )
2022-01-03 17:56:37 -05:00
{
return ResaveSizeTracker . GetBulkDataResaveSize ( PackageName ) ;
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : TickCook ( float DeltaTime , bool bTickComplete )
2021-06-24 00:51:58 -04:00
{
bool bWaitForCooldown = ! bTickComplete ;
2021-07-12 07:59:52 -04:00
check ( bActive ) ; // Ticks should not come in after we destruct
2021-06-24 00:51:58 -04:00
{
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
PruneTempLoadedPayloads ( ) ;
}
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : Tick ( float DeltaTime )
2021-06-24 00:51:58 -04:00
{
TickCook ( DeltaTime , false /* bTickComplete */ ) ;
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : AddPendingPackageBulkData ( FName PackageName , UE : : Serialization : : FEditorBulkData & & BulkData )
2021-06-24 00:51:58 -04:00
{
FScopeLock PendingPackageScopeLock ( & PendingPackageLock ) ;
2021-07-12 07:59:52 -04:00
check ( bActive ) ; // Registrations should not come in after we destruct, and AsyncTasks should check bActive before calling
2021-06-24 00:51:58 -04:00
TUniquePtr < FPendingPackage > & PendingPackage = PendingPackages . FindOrAdd ( PackageName ) ;
if ( ! PendingPackage . IsValid ( ) )
{
PendingPackage = MakeUnique < FPendingPackage > ( PackageName , this ) ;
}
2021-07-15 09:57:13 -04:00
if ( ! PendingPackage - > IsLoadInProgress ( ) )
{
return ;
}
2022-04-21 12:03:36 -04:00
PendingPackage - > AddBulkData ( MoveTemp ( BulkData ) ) ;
2021-06-24 00:51:58 -04:00
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : AddTempLoadedPayload ( const FGuid & RegistryKey , uint64 PayloadSize )
2021-06-24 00:51:58 -04:00
{
// Called within RegistryLock WriteLock
TempLoadedPayloads . Add ( FTempLoadedPayload { RegistryKey , PayloadSize , FPlatformTime : : Seconds ( ) + Constants : : TempLoadedPayloadsDuration } ) ;
TempLoadedPayloadsSize + = PayloadSize ;
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : PruneTempLoadedPayloads ( )
2021-06-24 00:51:58 -04:00
{
// Called within RegistryLock WriteLock
if ( ! TempLoadedPayloads . IsEmpty ( ) )
{
double CurrentTime = FPlatformTime : : Seconds ( ) ;
while ( ! TempLoadedPayloads . IsEmpty ( ) & &
( TempLoadedPayloadsSize > Constants : : TempLoadedPayloadsSizeBudget
| | TempLoadedPayloads [ 0 ] . EndTime < = CurrentTime ) )
{
FTempLoadedPayload Payload = TempLoadedPayloads . PopFrontValue ( ) ;
2021-07-12 07:59:52 -04:00
FRegisteredBulk * Existing = Registry . Find ( Payload . Guid ) ;
2021-06-24 00:51:58 -04:00
if ( Existing )
{
// UnloadData only unloads the in-memory data, and only if the BulkData can be reloaded from disk
Existing - > BulkData . UnloadData ( ) ;
2021-07-12 07:59:52 -04:00
Existing - > bHasTempPayload = false ;
2021-06-24 00:51:58 -04:00
}
TempLoadedPayloadsSize - = Payload . PayloadSize ;
}
}
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : WritePayloadIdToCache ( FName PackageName , const UE : : Serialization : : FEditorBulkData & BulkData ) const
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
check ( ! PackageName . IsNone ( ) ) ;
TArray < uint8 > Bytes ;
FMemoryWriter Writer ( Bytes ) ;
2022-01-21 09:18:53 -05:00
const_cast < UE : : Serialization : : FEditorBulkData & > ( BulkData ) . SerializeForRegistry ( Writer ) ;
2021-07-15 09:57:13 -04:00
UE : : EditorDomain : : PutBulkDataPayloadId ( PackageName , BulkData . GetIdentifier ( ) , MakeSharedBufferFromArray ( MoveTemp ( Bytes ) ) ) ;
}
2022-05-19 21:10:57 -04:00
void FBulkDataRegistryImpl : : ReadPayloadIdsFromCache ( FName PackageName , TArray < TRefCountPtr < FPendingPayloadId > > & & OldPendings ,
2021-08-04 18:08:50 -04:00
TArray < TRefCountPtr < FPendingPayloadId > > & & NewPendings )
2021-07-15 09:57:13 -04:00
{
// Cancel any old requests for the Guids in NewPendings; we are about to overwrite them
2021-08-04 18:08:50 -04:00
// This cancellation has to occur outside of any lock, since the task may be in progress and
2021-07-15 09:57:13 -04:00
// and to enter the lock and Cancel will wait on it
for ( TRefCountPtr < FPendingPayloadId > & OldPending : OldPendings )
{
2021-08-04 18:08:50 -04:00
OldPending - > Cancel ( ) ;
2021-07-15 09:57:13 -04:00
}
OldPendings . Empty ( ) ;
2021-08-04 18:08:50 -04:00
for ( TRefCountPtr < FPendingPayloadId > & NewPending : NewPendings )
2021-07-15 09:57:13 -04:00
{
// Creation of the Request has to occur outside of any lock, because the request
// may execute immediately on this thread and need to enter the lock; our locks are non-reentrant
2021-08-05 15:46:22 -04:00
UE : : DerivedData : : FRequestBarrier Barrier ( NewPending - > GetRequestOwner ( ) ) ;
UE : : EditorDomain : : GetBulkDataPayloadId ( PackageName , NewPending - > GetBulkDataId ( ) , NewPending - > GetRequestOwner ( ) ,
2021-07-15 09:57:13 -04:00
[ this , PackageName , NewPending ] ( FSharedBuffer Buffer )
{
if ( Buffer . IsNull ( ) )
{
return ;
}
FMemoryReaderView Reader ( MakeArrayView ( Buffer ) ) ;
2022-01-21 09:18:53 -05:00
UE : : Serialization : : FEditorBulkData CachedBulkData ;
2021-07-15 09:57:13 -04:00
CachedBulkData . SerializeForRegistry ( Reader ) ;
const FGuid & BulkDataId = NewPending - > GetBulkDataId ( ) ;
if ( Reader . IsError ( ) | | CachedBulkData . GetIdentifier ( ) ! = BulkDataId )
{
2022-04-21 12:03:36 -04:00
UE_LOG ( LogBulkDataRegistry , Warning , TEXT ( " Corrupt cache data for BulkDataPayloadId %s. " ) , WriteToString < 192 > ( PackageName , TEXT ( " / " ) , BulkDataId ) . ToString ( ) ) ;
2021-07-15 09:57:13 -04:00
return ;
}
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
if ( ! bActive )
{
return ;
}
TRefCountPtr < FPendingPayloadId > ExistingPending ;
if ( ! PendingPayloadIds . RemoveAndCopyValue ( BulkDataId , ExistingPending ) )
{
return ;
}
check ( ExistingPending - > GetBulkDataId ( ) = = BulkDataId ) ;
if ( ExistingPending ! = NewPending )
{
// We removed ExistingPending because we thought it was equal to NewPending, but it's not, so put it back
PendingPayloadIds . Add ( BulkDataId , MoveTemp ( ExistingPending ) ) ;
return ;
}
FRegisteredBulk * ExistingRegisteredBulk = Registry . Find ( BulkDataId ) ;
if ( ! ExistingRegisteredBulk )
{
return ;
}
2022-01-21 09:18:53 -05:00
UE : : Serialization : : FEditorBulkData & ExistingBulkData = ExistingRegisteredBulk - > BulkData ;
2021-07-15 09:57:13 -04:00
check ( ExistingBulkData . GetIdentifier ( ) = = BulkDataId ) ;
2022-04-21 12:03:36 -04:00
if ( ExistingBulkData . HasPlaceholderPayloadId ( ) & & CachedBulkData . LocationMatches ( ExistingBulkData ) )
2021-07-15 09:57:13 -04:00
{
ExistingBulkData = CachedBulkData ;
}
} ) ;
}
// Assign the Requests we just created to the data for each guid in the map,
// which has to be edited only within the lock
// If for any reason (race condition, shutting down) we can not assign a Request,
// we have to cancel the request before returning, to make sure the callback does not hold a pointer
// to this that could become dangling.
{
FWriteScopeLock RegistryScopeLock ( RegistryLock ) ;
if ( ! bActive )
{
2021-08-04 18:08:50 -04:00
for ( TRefCountPtr < FPendingPayloadId > & NewPending : NewPendings )
2021-07-15 09:57:13 -04:00
{
2021-08-04 18:08:50 -04:00
OldPendings . Add ( MoveTemp ( NewPending ) ) ;
2021-07-15 09:57:13 -04:00
}
}
else
{
2021-08-04 18:08:50 -04:00
for ( TRefCountPtr < FPendingPayloadId > & NewPending : NewPendings )
2021-07-15 09:57:13 -04:00
{
TRefCountPtr < FPendingPayloadId > * ExistingPending = PendingPayloadIds . Find ( NewPending - > GetBulkDataId ( ) ) ;
if ( ! ExistingPending | | * ExistingPending ! = NewPending )
{
OldPendings . Add ( MoveTemp ( NewPending ) ) ;
}
}
}
}
NewPendings . Empty ( ) ;
for ( TRefCountPtr < FPendingPayloadId > & OldPending : OldPendings )
{
2021-08-04 18:08:50 -04:00
OldPending - > Cancel ( ) ;
2021-07-15 09:57:13 -04:00
}
OldPendings . Empty ( ) ;
2021-06-24 00:51:58 -04:00
}
2022-05-19 21:10:57 -04:00
FPendingPackage : : FPendingPackage ( FName InPackageName , FBulkDataRegistryImpl * InOwner )
2021-06-24 00:51:58 -04:00
: PackageName ( InPackageName )
2021-08-05 15:46:22 -04:00
, BulkDataListCacheRequest ( UE : : DerivedData : : EPriority : : Low )
2021-06-24 00:51:58 -04:00
, Owner ( InOwner )
{
2021-07-15 09:57:13 -04:00
PendingOperations = Flag_EndLoad | Flag_BulkDataListResults ;
2021-08-04 18:08:50 -04:00
UE : : EditorDomain : : GetBulkDataList ( PackageName , BulkDataListCacheRequest ,
[ this ] ( FSharedBuffer Buffer ) { OnBulkDataListResults ( Buffer ) ; } ) ;
2021-06-24 00:51:58 -04:00
}
2021-07-15 09:57:13 -04:00
void FPendingPackage : : Cancel ( )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
// Called from outside Owner->PendingPackagesLock, so OnBulkDataList can complete on other thread while we wait
// Called after removing this from Owner->PendingPackages under a previous cover of the lock
// If OnBulkDataList is running on other thread its attempt to remove from PendingPackages will be a noop
2021-07-21 11:44:18 -04:00
if ( ! BulkDataListCacheRequest . Poll ( ) )
2021-07-15 09:57:13 -04:00
{
// Optimization: prevent WriteCache from running at all if we reach here first
PendingOperations . fetch_or ( Flag_Canceled ) ;
BulkDataListCacheRequest . Cancel ( ) ;
}
2021-06-24 00:51:58 -04:00
}
2021-07-15 09:57:13 -04:00
void FPendingPackage : : OnEndLoad ( bool & bOutShouldRemove , bool & bOutShouldWriteCache )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
// Called from within Owner->PendingPackageLock
bLoadInProgress = false ;
if ( PendingOperations . fetch_and ( ~ Flag_EndLoad ) = = Flag_EndLoad )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
bOutShouldWriteCache = true ;
bOutShouldRemove = true ;
2021-06-24 00:51:58 -04:00
}
2021-08-09 07:36:56 -04:00
else
{
bOutShouldWriteCache = false ;
bOutShouldRemove = false ;
}
2021-07-15 09:57:13 -04:00
}
2021-06-24 00:51:58 -04:00
2021-07-15 09:57:13 -04:00
void FPendingPackage : : OnBulkDataListResults ( FSharedBuffer Buffer )
{
if ( ! Buffer . IsNull ( ) )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
FMemoryReaderView Reader ( MakeArrayView ( Buffer ) ) ;
Serialize ( Reader , CachedBulkDatas ) ;
if ( Reader . IsError ( ) )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
CachedBulkDatas . Empty ( ) ;
2021-06-24 00:51:58 -04:00
}
2021-07-15 09:57:13 -04:00
}
ReadCache ( ) ;
if ( PendingOperations . fetch_and ( ~ Flag_BulkDataListResults ) = = Flag_BulkDataListResults )
{
2021-08-09 07:36:56 -04:00
// We do not hold a lock when writing the cache, so we need to remove this from PendingPackages
// before calling WriteCache to avoid other threads being able to access it.
TUniquePtr < FPendingPackage > ThisPointer ;
{
FScopeLock PendingPackageScopeLock ( & Owner - > PendingPackageLock ) ;
2022-03-02 17:49:21 -05:00
Owner - > PendingPackages . RemoveAndCopyValue ( PackageName , ThisPointer ) ;
// PackageName may have already been removed from PendingPackages if Owner is shutting down. In that case,
// ThisPointer will be null, and Owner holds the UniquePtr to *this.
// It will release that UniquePtr only after Cancel returns, which will be after this function returns.
2021-08-09 07:36:56 -04:00
}
2021-07-15 09:57:13 -04:00
WriteCache ( ) ;
2021-08-09 07:36:56 -04:00
// Deleting *this will destruct BulkDataListCacheRequest, which by
// default calls Cancel, but Cancel will block on this callback we are
// currently in. Direct the owner to keep requests alive to avoid that deadlock.
2021-08-04 18:08:50 -04:00
BulkDataListCacheRequest . KeepAlive ( ) ;
2021-08-09 07:36:56 -04:00
ThisPointer . Reset ( ) ;
2022-03-02 17:49:21 -05:00
// *this may have been deleted and can no longer be accessed
2021-07-15 09:57:13 -04:00
}
}
void FPendingPackage : : ReadCache ( )
{
if ( CachedBulkDatas . Num ( ) = = 0 )
{
return ;
}
TArray < TRefCountPtr < FPendingPayloadId > > OldPendings ;
2021-08-04 18:08:50 -04:00
TArray < TRefCountPtr < FPendingPayloadId > > NewPendings ;
2021-07-15 09:57:13 -04:00
// Add each CachedBulkData to the Registry, updating RawHash if it is missing.
// For every BulkData in this package in the Registry after the CachedBulkData has been added,
// if the RawHash is missing from the CachedBulkData as well, queue a read of its RawHash
// from the separate PlaceholderPayloadId BulkTablePayloadId cache bucket.
{
FWriteScopeLock RegistryScopeLock ( Owner - > RegistryLock ) ;
if ( ! Owner - > bActive )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
return ;
}
2022-01-21 09:18:53 -05:00
for ( const UE : : Serialization : : FEditorBulkData & BulkData : CachedBulkDatas )
2021-07-15 09:57:13 -04:00
{
FGuid BulkDataId = BulkData . GetIdentifier ( ) ;
FRegisteredBulk & TargetRegisteredBulk = Owner - > Registry . FindOrAdd ( BulkData . GetIdentifier ( ) ) ;
bool bCachedLocationMatches = true ;
2022-01-21 09:18:53 -05:00
UE : : Serialization : : FEditorBulkData & TargetBulkData = TargetRegisteredBulk . BulkData ;
2021-07-15 09:57:13 -04:00
if ( ! TargetBulkData . GetIdentifier ( ) . IsValid ( ) )
2021-06-24 00:51:58 -04:00
{
TargetBulkData = BulkData ;
2021-07-15 09:57:13 -04:00
TargetRegisteredBulk . PackageName = PackageName ;
2022-04-21 12:03:36 -04:00
TargetRegisteredBulk . bPayloadAvailable = true ;
2021-07-15 09:57:13 -04:00
}
else
{
check ( TargetBulkData . GetIdentifier ( ) = = BulkDataId ) ;
2022-04-21 12:03:36 -04:00
bCachedLocationMatches = BulkData . LocationMatches ( TargetBulkData ) ;
2021-07-15 09:57:13 -04:00
if ( bCachedLocationMatches & & ! BulkData . HasPlaceholderPayloadId ( ) & & TargetBulkData . HasPlaceholderPayloadId ( ) )
{
TargetBulkData = BulkData ;
TargetRegisteredBulk . PackageName = PackageName ;
2022-04-21 12:03:36 -04:00
TargetRegisteredBulk . bPayloadAvailable = true ;
2021-07-15 09:57:13 -04:00
}
}
if ( bCachedLocationMatches & & TargetBulkData . HasPlaceholderPayloadId ( ) )
{
2021-08-04 18:08:50 -04:00
NewPendings . Emplace ( new FPendingPayloadId ( BulkDataId ) ) ;
2021-07-15 09:57:13 -04:00
}
}
2021-08-04 18:08:50 -04:00
for ( TRefCountPtr < FPendingPayloadId > & NewPending : NewPendings )
2021-07-15 09:57:13 -04:00
{
2021-08-04 18:08:50 -04:00
TRefCountPtr < FPendingPayloadId > & ExistingPending = Owner - > PendingPayloadIds . FindOrAdd ( NewPending - > GetBulkDataId ( ) ) ;
if ( ExistingPending . IsValid ( ) )
2021-07-15 09:57:13 -04:00
{
2021-08-04 18:08:50 -04:00
OldPendings . Add ( MoveTemp ( ExistingPending ) ) ;
2021-06-24 00:51:58 -04:00
}
2021-08-04 18:08:50 -04:00
ExistingPending = NewPending ;
2021-06-24 00:51:58 -04:00
}
}
2021-07-15 09:57:13 -04:00
Owner - > ReadPayloadIdsFromCache ( PackageName , MoveTemp ( OldPendings ) , MoveTemp ( NewPendings ) ) ;
2021-06-24 00:51:58 -04:00
}
2021-07-15 09:57:13 -04:00
void FPendingPackage : : WriteCache ( )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
// If the BulkDataList cache read found some existing results, then exit; cache results are deterministic so there
// is no need to write the list to the cache again.
if ( CachedBulkDatas . Num ( ) > 0 )
{
return ;
}
2021-06-24 00:51:58 -04:00
2021-07-15 09:57:13 -04:00
check ( BulkDatas . Num ( ) > 0 ) ; // We should have >= 1 bulkdatas, or we would not have created the FPendingPackage
// Remove any duplicates in the runtime BulkDatas; elements later in the list override earlier elements
2021-06-24 00:51:58 -04:00
{
TSet < FGuid > BulkDataGuids ;
2021-07-15 09:57:13 -04:00
for ( int32 Index = BulkDatas . Num ( ) - 1 ; Index > = 0 ; - - Index )
2021-06-24 00:51:58 -04:00
{
bool bAlreadyExists ;
BulkDataGuids . Add ( BulkDatas [ Index ] . GetIdentifier ( ) , & bAlreadyExists ) ;
if ( bAlreadyExists )
{
BulkDatas . RemoveAt ( Index ) ;
}
}
}
2021-07-15 09:57:13 -04:00
// Sort the list by guid, to avoid indeterminism in the list
2022-01-21 09:18:53 -05:00
BulkDatas . Sort ( [ ] ( const UE : : Serialization : : FEditorBulkData & A , const UE : : Serialization : : FEditorBulkData & B )
2021-06-24 00:51:58 -04:00
{
2021-07-15 09:57:13 -04:00
return A . GetIdentifier ( ) < B . GetIdentifier ( ) ;
} ) ;
2021-06-24 00:51:58 -04:00
2021-07-15 09:57:13 -04:00
TArray < uint8 > Bytes ;
FMemoryWriter Writer ( Bytes ) ;
Serialize ( Writer , BulkDatas ) ;
UE : : EditorDomain : : PutBulkDataList ( PackageName , MakeSharedBufferFromArray ( MoveTemp ( Bytes ) ) ) ;
2021-06-24 00:51:58 -04:00
}
2022-05-19 21:10:57 -04:00
FUpdatePayloadWorker : : FUpdatePayloadWorker ( FBulkDataRegistryImpl * InBulkDataRegistry ,
2022-01-21 09:18:53 -05:00
const UE : : Serialization : : FEditorBulkData & InSourceBulk )
2021-07-12 07:59:52 -04:00
: BulkData ( InSourceBulk )
, BulkDataRegistry ( InBulkDataRegistry )
{
SharedDataLock = InBulkDataRegistry - > SharedDataLock ;
}
void FUpdatePayloadWorker : : DoWork ( )
{
FUpdatingPayload LocalUpdatingPayload ;
FCompressedBuffer Buffer ;
bool bValid = true ;
for ( ; ; )
{
BulkData . UpdatePayloadId ( ) ;
Buffer = BulkData . GetCompressedPayload ( ) . Get ( ) ;
{
FReadScopeLock SharedDataScopeLock ( SharedDataLock - > ActiveLock ) ;
if ( ! SharedDataLock - > bActive )
{
// The BulkDataRegistry has destructed. Our list of requesters is on the BulkDataRegistry, so there's nothing we can do except exit
return ;
}
FWriteScopeLock RegistryScopeLock ( BulkDataRegistry - > RegistryLock ) ;
if ( ! BulkDataRegistry - > UpdatingPayloads . RemoveAndCopyValue ( BulkData . GetIdentifier ( ) , LocalUpdatingPayload ) )
{
// The updating payload might not exist in the case of the Registry shutting down; it will clear the UpdatingPayloads to cancel our action
// Return canceled (which we treat the same as failed) to our requesters
bValid = false ;
break ;
}
check ( BulkDataRegistry - > bActive ) ; // Only set to false at the same time as SharedDataLock->bActive
FRegisteredBulk * RegisteredBulk = BulkDataRegistry - > Registry . Find ( BulkData . GetIdentifier ( ) ) ;
if ( ! RegisteredBulk )
{
// Some agent has deregistered the BulkData before we finished calculating its payload
// return failure to our requesters
bValid = false ;
break ;
}
2022-04-21 12:03:36 -04:00
if ( ! BulkData . LocationMatches ( RegisteredBulk - > BulkData ) )
2021-07-12 07:59:52 -04:00
{
// Some caller has assigned a new BulkData. We need to abandon the BulkData we just loaded and give our callers the
// information about the new one
check ( RegisteredBulk - > BulkData . GetIdentifier ( ) = = BulkData . GetIdentifier ( ) ) ; // The identifier in the BulkData should match the key for that BulkData in Registry
BulkData = RegisteredBulk - > BulkData ;
// Add our LocalUpdatingPayload back to UpdatingPayloads; we removed it because we thought we were done.
BulkDataRegistry - > UpdatingPayloads . Add ( BulkData . GetIdentifier ( ) , MoveTemp ( LocalUpdatingPayload ) ) ;
continue ;
}
2022-04-21 12:03:36 -04:00
// Store the new PayloadId in the Registry's entry for the BulkData; new MetaData requests will no longer need to wait for it
2021-07-12 07:59:52 -04:00
RegisteredBulk - > BulkData = BulkData ;
// Mark that the next GetData call should remove the temporary payload
RegisteredBulk - > bHasTempPayload = true ;
BulkDataRegistry - > AddTempLoadedPayload ( BulkData . GetIdentifier ( ) , BulkData . GetPayloadSize ( ) ) ;
BulkDataRegistry - > PruneTempLoadedPayloads ( ) ;
2022-04-21 12:03:36 -04:00
if ( RegisteredBulk - > bAllowedToWritePayloadIdToCache )
2021-07-12 07:59:52 -04:00
{
2021-07-15 09:57:13 -04:00
BulkDataRegistry - > WritePayloadIdToCache ( RegisteredBulk - > PackageName , BulkData ) ;
2022-04-21 12:03:36 -04:00
RegisteredBulk - > bAllowedToWritePayloadIdToCache = false ;
2021-07-12 07:59:52 -04:00
}
break ;
}
}
if ( ! bValid )
{
Buffer . Reset ( ) ;
}
for ( TUniqueFunction < void ( bool , const FCompressedBuffer & ) > & Requester : LocalUpdatingPayload . Requesters )
{
Requester ( bValid , Buffer ) ;
}
}
2021-08-04 18:08:50 -04:00
FPendingPayloadId : : FPendingPayloadId ( const FGuid & InBulkDataId )
: BulkDataId ( InBulkDataId )
2021-08-05 15:46:22 -04:00
, Request ( UE : : DerivedData : : EPriority : : Low )
2021-08-04 18:08:50 -04:00
{
2021-10-25 20:05:28 -04:00
// The last reference to this can be released by the completion callback, which will deadlock
// trying to cancel the request. KeepAlive skips cancellation in the destructor.
Request . KeepAlive ( ) ;
2021-08-04 18:08:50 -04:00
}
2021-07-15 09:57:13 -04:00
void FPendingPayloadId : : Cancel ( )
{
Request . Cancel ( ) ;
}
2022-01-21 09:18:53 -05:00
void Serialize ( FArchive & Ar , TArray < UE : : Serialization : : FEditorBulkData > & Datas )
2021-06-24 00:51:58 -04:00
{
int32 Num = Datas . Num ( ) ;
Ar < < Num ;
const uint32 MinSize = 4 ;
if ( Ar . IsLoading ( ) )
{
if ( Ar . IsError ( ) | | Num * MinSize > Ar . TotalSize ( ) - Ar . Tell ( ) )
{
Ar . SetError ( ) ;
Datas . Empty ( ) ;
return ;
}
else
{
Datas . Empty ( Num ) ;
}
for ( int32 n = 0 ; n < Num ; + + n )
{
2022-01-21 09:18:53 -05:00
UE : : Serialization : : FEditorBulkData & BulkData = Datas . Emplace_GetRef ( ) ;
2021-06-24 00:51:58 -04:00
BulkData . SerializeForRegistry ( Ar ) ;
}
}
else
{
2022-01-21 09:18:53 -05:00
for ( UE : : Serialization : : FEditorBulkData & BulkData : Datas )
2021-06-24 00:51:58 -04:00
{
BulkData . SerializeForRegistry ( Ar ) ;
}
}
}
} // namespace UE::BulkDataRegistry::Private