2021-06-15 16:38:03 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "ZenStoreWriter.h"
# include "ZenStoreHttpClient.h"
# include "ZenFileSystemManifest.h"
# include "PackageStoreOptimizer.h"
2021-09-08 07:04:39 -04:00
# include "Algo/BinarySearch.h"
# include "Algo/IsSorted.h"
# include "Algo/Sort.h"
2021-09-17 09:32:48 -04:00
# include "AssetRegistry/AssetRegistryState.h"
2021-06-15 16:38:03 -04:00
# include "Async/Async.h"
2021-11-07 23:43:01 -05:00
# include "Containers/Queue.h"
2021-09-17 09:32:48 -04:00
# include "Serialization/ArrayReader.h"
2021-06-15 16:38:03 -04:00
# include "Serialization/CompactBinaryPackage.h"
# include "Serialization/CompactBinaryWriter.h"
# include "Serialization/LargeMemoryWriter.h"
# include "HAL/FileManager.h"
# include "HAL/PlatformFileManager.h"
# include "IO/IoDispatcher.h"
# include "Misc/App.h"
2022-04-19 02:37:06 -04:00
# include "Misc/CommandLine.h"
2021-09-17 09:32:48 -04:00
# include "Misc/FileHelper.h"
2021-08-12 10:51:31 -04:00
# include "Misc/StringBuilder.h"
2021-06-15 16:38:03 -04:00
# include "Interfaces/ITargetPlatform.h"
# include "Misc/Paths.h"
# include "GenericPlatform/GenericPlatformFile.h"
2021-10-25 20:05:28 -04:00
# include "UObject/SavePackage.h"
2021-06-15 16:38:03 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogZenStoreWriter , Log , All ) ;
using namespace UE ;
2021-08-12 10:51:31 -04:00
// Note that this is destructive - we yank out the buffer memory from the
// IoBuffer into the FSharedBuffer
FSharedBuffer IoBufferToSharedBuffer ( FIoBuffer & InBuffer )
{
InBuffer . EnsureOwned ( ) ;
const uint64 DataSize = InBuffer . DataSize ( ) ;
uint8 * DataPtr = InBuffer . Release ( ) . ValueOrDie ( ) ;
return FSharedBuffer { FSharedBuffer : : TakeOwnership ( DataPtr , DataSize , FMemory : : Free ) } ;
} ;
2021-06-15 16:38:03 -04:00
FCbObjectId ToObjectId ( const FIoChunkId & ChunkId )
{
return FCbObjectId ( MakeMemoryView ( ChunkId . GetData ( ) , ChunkId . GetSize ( ) ) ) ;
}
2021-06-23 09:01:23 -04:00
FMD5Hash IoHashToMD5 ( const FIoHash & IoHash )
{
const FIoHash : : ByteArray & Bytes = IoHash . GetBytes ( ) ;
FMD5 MD5Gen ;
MD5Gen . Update ( Bytes , sizeof ( FIoHash : : ByteArray ) ) ;
FMD5Hash Hash ;
Hash . Set ( MD5Gen ) ;
return Hash ;
}
2022-05-18 14:49:11 -04:00
struct FZenStoreWriter : : FZenCommitInfo
{
IPackageWriter : : FCommitPackageInfo CommitInfo ;
TUniquePtr < FPendingPackageState > PackageState ;
} ;
2021-11-07 23:43:01 -05:00
class FZenStoreWriter : : FCommitQueue
2021-06-15 16:38:03 -04:00
{
public :
2021-11-07 23:43:01 -05:00
FCommitQueue ( )
: NewCommitEvent ( EEventMode : : AutoReset )
, QueueEmptyEvent ( EEventMode : : ManualReset ) { }
2022-05-18 14:49:11 -04:00
void Enqueue ( FZenCommitInfo & & Commit )
2021-06-15 16:38:03 -04:00
{
{
FScopeLock _ ( & QueueCriticalSection ) ;
2022-05-18 14:49:11 -04:00
Queue . Enqueue ( MoveTemp ( Commit ) ) ;
2021-11-07 23:43:01 -05:00
QueueNum + + ;
}
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
NewCommitEvent - > Trigger ( ) ;
}
2022-05-18 14:49:11 -04:00
bool BlockAndDequeue ( FZenCommitInfo & OutCommit )
2021-11-07 23:43:01 -05:00
{
for ( ; ; )
{
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FScopeLock _ ( & QueueCriticalSection ) ;
if ( Queue . Dequeue ( OutCommit ) )
{
QueueNum - - ;
return true ;
}
QueueEmptyEvent - > Trigger ( ) ;
2021-06-15 16:38:03 -04:00
}
2021-11-07 23:43:01 -05:00
if ( bCompleteAdding )
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
return false ;
}
NewCommitEvent - > Wait ( ) ;
}
}
void CompleteAdding ( )
{
bCompleteAdding = true ;
NewCommitEvent - > Trigger ( ) ;
}
2021-12-10 18:06:39 -05:00
void ResetAdding ( )
{
bCompleteAdding = false ;
}
2021-11-07 23:43:01 -05:00
void WaitUntilEmpty ( )
{
bool bWait = false ;
{
FScopeLock _ ( & QueueCriticalSection ) ;
if ( QueueNum > 0 )
{
QueueEmptyEvent - > Reset ( ) ;
bWait = true ;
2021-06-15 16:38:03 -04:00
}
}
2021-11-07 23:43:01 -05:00
if ( bWait )
{
QueueEmptyEvent - > Wait ( ) ;
}
2021-06-15 16:38:03 -04:00
}
private :
2021-11-07 23:43:01 -05:00
FEventRef NewCommitEvent ;
FEventRef QueueEmptyEvent ;
FCriticalSection QueueCriticalSection ;
2022-05-18 14:49:11 -04:00
TQueue < FZenCommitInfo > Queue ;
2021-11-07 23:43:01 -05:00
int32 QueueNum = 0 ;
TAtomic < bool > bCompleteAdding { false } ;
2021-06-15 16:38:03 -04:00
} ;
2021-09-08 07:04:39 -04:00
TArray < const UTF8CHAR * > FZenStoreWriter : : ReservedOplogKeys ;
void FZenStoreWriter : : StaticInit ( )
{
if ( ReservedOplogKeys . Num ( ) > 0 )
{
return ;
}
ReservedOplogKeys . Append ( { UTF8TEXT ( " files " ) , UTF8TEXT ( " key " ) , UTF8TEXT ( " package " ) , UTF8TEXT ( " packagestoreentry " ) } ) ;
Algo : : Sort ( ReservedOplogKeys , [ ] ( const UTF8CHAR * A , const UTF8CHAR * B )
{
return FUtf8StringView ( A ) . Compare ( FUtf8StringView ( B ) , ESearchCase : : IgnoreCase ) < 0 ;
} ) ; ;
}
2021-06-15 16:38:03 -04:00
FZenStoreWriter : : FZenStoreWriter (
const FString & InOutputPath ,
const FString & InMetadataDirectoryPath ,
2021-08-20 10:57:45 -04:00
const ITargetPlatform * InTargetPlatform
)
2021-06-15 16:38:03 -04:00
: TargetPlatform ( * InTargetPlatform )
2022-02-17 04:54:33 -05:00
, TargetPlatformFName ( * InTargetPlatform - > PlatformName ( ) )
2021-06-15 16:38:03 -04:00
, OutputPath ( InOutputPath )
, MetadataDirectoryPath ( InMetadataDirectoryPath )
2021-09-15 10:39:23 -04:00
, PackageStoreManifest ( InOutputPath )
2021-06-15 16:38:03 -04:00
, PackageStoreOptimizer ( new FPackageStoreOptimizer ( ) )
2021-08-20 10:02:58 -04:00
, CookMode ( ICookedPackageWriter : : FCookInfo : : CookByTheBookMode )
2021-08-20 10:57:45 -04:00
, bInitialized ( false )
2021-06-15 16:38:03 -04:00
{
2021-09-08 07:04:39 -04:00
StaticInit ( ) ;
2022-05-23 01:49:25 -04:00
ProjectId = FApp : : GetZenStoreProjectId ( ) ;
2022-04-19 02:37:06 -04:00
if ( FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " -ZenStorePlatform= " ) , OplogId ) = = false )
{
OplogId = InTargetPlatform - > PlatformName ( ) ;
}
2021-09-22 13:00:17 -04:00
HttpClient = MakeUnique < UE : : FZenStoreHttpClient > ( ) ;
2021-06-15 16:38:03 -04:00
FString RootDir = FPaths : : RootDir ( ) ;
FString EngineDir = FPaths : : EngineDir ( ) ;
FPaths : : NormalizeDirectoryName ( EngineDir ) ;
FString ProjectDir = FPaths : : ProjectDir ( ) ;
FPaths : : NormalizeDirectoryName ( ProjectDir ) ;
IPlatformFile & PlatformFile = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
FString AbsServerRoot = PlatformFile . ConvertToAbsolutePathForExternalAppForRead ( * RootDir ) ;
FString AbsEngineDir = PlatformFile . ConvertToAbsolutePathForExternalAppForRead ( * EngineDir ) ;
FString AbsProjectDir = PlatformFile . ConvertToAbsolutePathForExternalAppForRead ( * ProjectDir ) ;
2021-09-29 10:51:17 -04:00
HttpClient - > TryCreateProject ( ProjectId , OplogId , AbsServerRoot , AbsEngineDir , AbsProjectDir ) ;
2021-06-15 16:38:03 -04:00
2021-10-12 21:21:22 -04:00
PackageStoreOptimizer - > Initialize ( ) ;
2021-06-15 16:38:03 -04:00
FPackageStoreManifest : : FZenServerInfo & ZenServerInfo = PackageStoreManifest . EditZenServerInfo ( ) ;
2021-10-25 20:05:28 -04:00
# if UE_WITH_ZEN
const UE : : Zen : : FZenServiceInstance & ZenServiceInstance = HttpClient - > GetZenServiceInstance ( ) ;
2021-11-18 14:37:34 -05:00
ZenServerInfo . Settings = ZenServiceInstance . GetServiceSettings ( ) ;
2021-10-25 20:05:28 -04:00
# endif
2021-06-15 16:38:03 -04:00
ZenServerInfo . ProjectId = ProjectId ;
ZenServerInfo . OplogId = OplogId ;
ZenFileSystemManifest = MakeUnique < FZenFileSystemManifest > ( TargetPlatform , OutputPath ) ;
2021-11-07 23:43:01 -05:00
CommitQueue = MakeUnique < FCommitQueue > ( ) ;
2021-10-25 20:05:28 -04:00
Compressor = FOodleDataCompression : : ECompressor : : Mermaid ;
CompressionLevel = FOodleDataCompression : : ECompressionLevel : : VeryFast ;
2021-06-15 16:38:03 -04:00
}
FZenStoreWriter : : ~ FZenStoreWriter ( )
{
2021-11-07 23:43:01 -05:00
FScopeLock _ ( & PackagesCriticalSection ) ;
2021-06-15 16:38:03 -04:00
if ( PendingPackages . Num ( ) )
{
UE_LOG ( LogZenStoreWriter , Warning , TEXT ( " Pending packages at shutdown! " ) ) ;
}
}
2021-10-25 20:05:28 -04:00
void FZenStoreWriter : : WritePackageData ( const FPackageInfo & Info , FLargeMemoryWriter & ExportsArchive , const TArray < FFileRegion > & FileRegions )
2021-06-15 16:38:03 -04:00
{
check ( Info . ChunkId . IsValid ( ) ) ;
2021-11-01 17:20:22 -04:00
int64 DataSize = ExportsArchive . TotalSize ( ) ;
FIoBuffer PackageData ( FIoBuffer : : AssumeOwnership , ExportsArchive . ReleaseOwnership ( ) , DataSize ) ;
2021-06-15 16:38:03 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( FZenStoreWriter : : WritePackageData ) ;
FIoBuffer CookedHeaderBuffer = FIoBuffer ( PackageData . Data ( ) , Info . HeaderSize , PackageData ) ;
FIoBuffer CookedExportsBuffer = FIoBuffer ( PackageData . Data ( ) + Info . HeaderSize , PackageData . DataSize ( ) - Info . HeaderSize , PackageData ) ;
2022-04-25 07:37:07 -04:00
TUniquePtr < FPackageStorePackage > Package { PackageStoreOptimizer - > CreatePackageFromCookedHeader ( Info . PackageName , CookedHeaderBuffer ) } ;
2021-06-15 16:38:03 -04:00
PackageStoreOptimizer - > FinalizePackage ( Package . Get ( ) ) ;
TArray < FFileRegion > FileRegionsCopy ( FileRegions ) ;
for ( FFileRegion & Region : FileRegionsCopy )
{
// Adjust regions so they are relative to the start of the exports buffer
Region . Offset - = Info . HeaderSize ;
}
FIoBuffer PackageBuffer = PackageStoreOptimizer - > CreatePackageBuffer ( Package . Get ( ) , CookedExportsBuffer , & FileRegionsCopy ) ;
2022-04-25 07:37:07 -04:00
PackageStoreManifest . AddPackageData ( Info . PackageName , Info . LooseFilePath , Info . ChunkId ) ;
2021-06-15 16:38:03 -04:00
for ( FFileRegion & Region : FileRegionsCopy )
{
// Adjust regions once more so they are relative to the exports bundle buffer
Region . Offset - = Package - > GetHeaderSize ( ) ;
}
//WriteFileRegions(*FPaths::ChangeExtension(Info.LooseFilePath, FString(".uexp") + FFileRegion::RegionsFileExtension), FileRegionsCopy);
// Commit to Zen build store
FCbObjectId ChunkOid = ToObjectId ( Info . ChunkId ) ;
2022-04-25 07:37:07 -04:00
FPendingPackageState & ExistingState = GetPendingPackage ( Info . PackageName ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
FPackageDataEntry & Entry = ExistingState . PackageData ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
Entry . CompressedPayload = Async ( EAsyncExecution : : TaskGraph , [ this , PackageBuffer ] ( )
{
return FCompressedBuffer : : Compress ( FSharedBuffer : : MakeView ( PackageBuffer . GetView ( ) ) , Compressor , CompressionLevel ) ;
} ) ;
2021-06-15 16:38:03 -04:00
Entry . Info = Info ;
Entry . ChunkId = ChunkOid ;
2022-04-25 07:37:07 -04:00
Entry . PackageStoreEntry = PackageStoreOptimizer - > CreatePackageStoreEntry ( Package . Get ( ) , nullptr ) ; // TODO: Can we separate out the optional segment package store entry and do this when we commit instead?
2021-06-15 16:38:03 -04:00
Entry . IsValid = true ;
2022-02-17 04:54:33 -05:00
if ( EntryCreatedEvent . IsBound ( ) )
{
IPackageStoreWriter : : FEntryCreatedEventArgs EntryCreatedEventArgs
{
TargetPlatformFName ,
Entry . PackageStoreEntry
} ;
EntryCreatedEvent . Broadcast ( EntryCreatedEventArgs ) ;
}
2021-06-15 16:38:03 -04:00
}
void FZenStoreWriter : : WriteIoStorePackageData ( const FPackageInfo & Info , const FIoBuffer & PackageData , const FPackageStoreEntryResource & PackageStoreEntry , const TArray < FFileRegion > & FileRegions )
{
check ( Info . ChunkId . IsValid ( ) ) ;
TRACE_CPUPROFILER_EVENT_SCOPE ( WriteIoStorePackageData ) ;
2022-04-25 07:37:07 -04:00
PackageStoreManifest . AddPackageData ( Info . PackageName , Info . LooseFilePath , Info . ChunkId ) ;
2021-06-15 16:38:03 -04:00
//WriteFileRegions(*FPaths::ChangeExtension(Info.LooseFilePath, FString(".uexp") + FFileRegion::RegionsFileExtension), FileRegionsCopy);
FCbObjectId ChunkOid = ToObjectId ( Info . ChunkId ) ;
2022-04-25 07:37:07 -04:00
FPendingPackageState & ExistingState = GetPendingPackage ( Info . PackageName ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
FPackageDataEntry & Entry = ExistingState . PackageData ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
PackageData . EnsureOwned ( ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
Entry . CompressedPayload = Async ( EAsyncExecution : : TaskGraph , [ this , PackageData ] ( )
{
return FCompressedBuffer : : Compress ( FSharedBuffer : : MakeView ( PackageData . GetView ( ) ) , Compressor , CompressionLevel ) ;
} ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
Entry . Info = Info ;
Entry . ChunkId = ChunkOid ;
2021-06-15 16:38:03 -04:00
Entry . PackageStoreEntry = PackageStoreEntry ;
2021-11-07 23:43:01 -05:00
Entry . IsValid = true ;
2021-06-15 16:38:03 -04:00
}
2021-10-25 20:05:28 -04:00
void FZenStoreWriter : : WriteBulkData ( const FBulkDataInfo & Info , const FIoBuffer & BulkData , const TArray < FFileRegion > & FileRegions )
2021-06-15 16:38:03 -04:00
{
check ( Info . ChunkId . IsValid ( ) ) ;
FCbObjectId ChunkOid = ToObjectId ( Info . ChunkId ) ;
2022-04-25 07:37:07 -04:00
FPendingPackageState & ExistingState = GetPendingPackage ( Info . PackageName ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
FBulkDataEntry & BulkEntry = ExistingState . BulkData . AddDefaulted_GetRef ( ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
BulkData . EnsureOwned ( ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
BulkEntry . CompressedPayload = Async ( EAsyncExecution : : TaskGraph , [ this , BulkData ] ( )
{
return FCompressedBuffer : : Compress ( FSharedBuffer : : MakeView ( BulkData . GetView ( ) ) , Compressor , CompressionLevel ) ;
} ) ;
2021-06-15 16:38:03 -04:00
BulkEntry . Info = Info ;
BulkEntry . ChunkId = ChunkOid ;
BulkEntry . IsValid = true ;
2022-04-25 07:37:07 -04:00
PackageStoreManifest . AddBulkData ( Info . PackageName , Info . LooseFilePath , Info . ChunkId ) ;
2021-06-15 16:38:03 -04:00
// WriteFileRegions(*(Info.LooseFilePath + FFileRegion::RegionsFileExtension), FileRegions);
}
2021-10-25 20:05:28 -04:00
void FZenStoreWriter : : WriteAdditionalFile ( const FAdditionalFileInfo & Info , const FIoBuffer & FileData )
2021-06-15 16:38:03 -04:00
{
2021-06-23 09:01:23 -04:00
const FZenFileSystemManifest : : FManifestEntry & ManifestEntry = ZenFileSystemManifest - > CreateManifestEntry ( Info . Filename ) ;
2021-11-07 23:43:01 -05:00
2022-04-25 07:37:07 -04:00
FPendingPackageState & ExistingState = GetPendingPackage ( Info . PackageName ) ;
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
FFileDataEntry & FileEntry = ExistingState . FileData . AddDefaulted_GetRef ( ) ;
FileData . EnsureOwned ( ) ;
FileEntry . CompressedPayload = Async ( EAsyncExecution : : TaskGraph , [ this , FileData ] ( )
{
return FCompressedBuffer : : Compress ( FSharedBuffer : : MakeView ( FileData . GetView ( ) ) , Compressor , CompressionLevel ) ;
} ) ;
2021-06-15 16:38:03 -04:00
FileEntry . Info = Info ;
2021-06-23 09:01:23 -04:00
FileEntry . Info . ChunkId = ManifestEntry . FileChunkId ;
2021-06-15 16:38:03 -04:00
FileEntry . ZenManifestServerPath = ManifestEntry . ServerPath ;
FileEntry . ZenManifestClientPath = ManifestEntry . ClientPath ;
}
2021-08-02 08:36:21 -04:00
void FZenStoreWriter : : WriteLinkerAdditionalData ( const FLinkerAdditionalDataInfo & Info , const FIoBuffer & Data , const TArray < FFileRegion > & FileRegions )
{
2021-10-12 21:21:22 -04:00
// LinkerAdditionalData is not yet implemented in this writer; it is only used for VirtualizedBulkData which is not used in cooked content
checkNoEntry ( ) ;
}
2021-10-25 20:05:28 -04:00
void FZenStoreWriter : : Initialize ( const FCookInfo & Info )
2021-06-15 16:38:03 -04:00
{
CookMode = Info . CookMode ;
2021-08-20 10:57:45 -04:00
if ( ! bInitialized )
{
2021-10-25 20:05:28 -04:00
if ( Info . bFullBuild )
{
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Deleting %s... " ) , * OutputPath ) ;
const bool bRequireExists = false ;
const bool bTree = true ;
IFileManager : : Get ( ) . DeleteDirectory ( * OutputPath , bRequireExists , bTree ) ;
}
2021-09-29 10:51:17 -04:00
bool bOplogEstablished = HttpClient - > TryCreateOplog ( ProjectId , OplogId , Info . bFullBuild ) ;
UE_CLOG ( ! bOplogEstablished , LogZenStoreWriter , Fatal , TEXT ( " Failed to establish oplog on the ZenServer " ) ) ;
2021-08-20 10:57:45 -04:00
2021-08-31 17:28:15 -04:00
if ( ! Info . bFullBuild )
2021-08-20 10:57:45 -04:00
{
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Fetching oplog... " ) , * ProjectId , * OplogId ) ;
TFuture < FIoStatus > FutureOplogStatus = HttpClient - > GetOplog ( ) . Next ( [ this ] ( TIoStatusOr < FCbObject > OplogStatus )
{
if ( ! OplogStatus . IsOk ( ) )
{
return OplogStatus . Status ( ) ;
}
FCbObject Oplog = OplogStatus . ConsumeValueOrDie ( ) ;
if ( Oplog [ " entries " ] )
{
for ( FCbField & OplogEntry : Oplog [ " entries " ] . AsArray ( ) )
{
FCbObject OplogObj = OplogEntry . AsObject ( ) ;
if ( OplogObj [ " package " ] )
{
FCbObject PackageObj = OplogObj [ " package " ] . AsObject ( ) ;
const FGuid PkgGuid = PackageObj [ " guid " ] . AsUuid ( ) ;
const FIoHash PkgHash = PackageObj [ " data " ] . AsHash ( ) ;
const int64 PkgDiskSize = PackageObj [ " disksize " ] . AsUInt64 ( ) ;
FPackageStoreEntryResource Entry = FPackageStoreEntryResource : : FromCbObject ( OplogObj [ " packagestoreentry " ] . AsObject ( ) ) ;
const FName PackageName = Entry . PackageName ;
2021-09-08 07:04:39 -04:00
2021-08-20 10:57:45 -04:00
const int32 Index = PackageStoreEntries . Num ( ) ;
PackageStoreEntries . Add ( MoveTemp ( Entry ) ) ;
2021-09-08 07:04:39 -04:00
FOplogCookInfo & CookInfo = CookedPackagesInfo . Add_GetRef (
FOplogCookInfo {
FCookedPackageInfo { PackageName , IoHashToMD5 ( PkgHash ) , PkgGuid , PkgDiskSize }
} ) ;
2021-08-20 10:57:45 -04:00
PackageNameToIndex . Add ( PackageName , Index ) ;
2021-09-08 07:04:39 -04:00
for ( FCbFieldView Field : OplogObj )
{
FUtf8StringView FieldName = Field . GetName ( ) ;
if ( IsReservedOplogKey ( FieldName ) )
{
continue ;
}
if ( Field . IsHash ( ) )
{
const UTF8CHAR * AttachmentId = UE : : FZenStoreHttpClient : : FindOrAddAttachmentId ( FieldName ) ;
CookInfo . Attachments . Add ( { AttachmentId , Field . AsHash ( ) } ) ;
}
}
CookInfo . Attachments . Shrink ( ) ;
check ( Algo : : IsSorted ( CookInfo . Attachments ,
[ ] ( const FOplogCookInfo : : FAttachment & A , const FOplogCookInfo : : FAttachment & B )
{
return FUtf8StringView ( A . Key ) . Compare ( FUtf8StringView ( B . Key ) , ESearchCase : : IgnoreCase ) < 0 ;
} ) ) ;
2021-08-20 10:57:45 -04:00
}
}
}
return FIoStatus : : Ok ;
} ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Fetching file manifest... " ) , * ProjectId , * OplogId ) ;
TIoStatusOr < FCbObject > FileStatus = HttpClient - > GetFiles ( ) . Get ( ) ;
if ( FileStatus . IsOk ( ) )
{
FCbObject FilesObj = FileStatus . ConsumeValueOrDie ( ) ;
for ( FCbField & FileEntry : FilesObj [ " files " ] )
{
FCbObject FileObj = FileEntry . AsObject ( ) ;
FCbObjectId FileId = FileObj [ " id " ] . AsObjectId ( ) ;
FString ServerPath = FString ( FileObj [ " serverpath " ] . AsString ( ) ) ;
FString ClientPath = FString ( FileObj [ " clientpath " ] . AsString ( ) ) ;
FIoChunkId FileChunkId ;
FileChunkId . Set ( FileId . GetView ( ) ) ;
ZenFileSystemManifest - > AddManifestEntry ( FileChunkId , MoveTemp ( ServerPath ) , MoveTemp ( ClientPath ) ) ;
}
2022-03-28 05:50:13 -04:00
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Fetched '%d' file(s) from oplog '%s/%s' " ) , ZenFileSystemManifest - > NumEntries ( ) , * ProjectId , * OplogId ) ;
2021-08-20 10:57:45 -04:00
}
else
{
UE_LOG ( LogZenStoreWriter , Warning , TEXT ( " Failed to fetch file(s) from oplog '%s/%s' " ) , * ProjectId , * OplogId ) ;
}
if ( FutureOplogStatus . Get ( ) . IsOk ( ) )
{
2021-09-16 03:18:06 -04:00
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Fetched '%d' packages(s) from oplog '%s/%s' " ) , PackageStoreEntries . Num ( ) , * ProjectId , * OplogId ) ;
2021-08-20 10:57:45 -04:00
}
else
{
UE_LOG ( LogZenStoreWriter , Warning , TEXT ( " Failed to fetch oplog '%s/%s' " ) , * ProjectId , * OplogId ) ;
}
}
bInitialized = true ;
}
else
{
2021-08-31 17:28:15 -04:00
if ( Info . bFullBuild )
2021-08-20 10:57:45 -04:00
{
RemoveCookedPackages ( ) ;
}
}
2021-10-25 20:05:28 -04:00
}
2021-08-20 10:57:45 -04:00
2021-10-25 20:05:28 -04:00
void FZenStoreWriter : : BeginCook ( )
{
2021-12-15 03:42:08 -05:00
PackageStoreManifest . Load ( * ( MetadataDirectoryPath / TEXT ( " packagestore.manifest " ) ) ) ;
2022-04-04 13:26:27 -04:00
AllPackageHashes . Empty ( ) ;
2021-12-15 03:42:08 -05:00
2021-10-25 20:05:28 -04:00
if ( CookMode = = ICookedPackageWriter : : FCookInfo : : CookOnTheFlyMode )
2021-06-15 16:38:03 -04:00
{
FCbPackage Pkg ;
FCbWriter PackageObj ;
PackageObj . BeginObject ( ) ;
PackageObj < < " key " < < " CookOnTheFly " ;
const bool bGenerateContainerHeader = false ;
CreateProjectMetaData ( Pkg , PackageObj , bGenerateContainerHeader ) ;
PackageObj . EndObject ( ) ;
FCbObject Obj = PackageObj . Save ( ) . AsObject ( ) ;
Pkg . SetObject ( Obj ) ;
2021-10-25 20:05:28 -04:00
TIoStatusOr < uint64 > Status = HttpClient - > AppendOp ( Pkg ) ;
2021-06-15 16:38:03 -04:00
UE_CLOG ( ! Status . IsOk ( ) , LogZenStoreWriter , Fatal , TEXT ( " Failed to append OpLog " ) ) ;
}
2021-11-07 23:43:01 -05:00
if ( FPlatformProcess : : SupportsMultithreading ( ) )
{
2021-12-10 18:06:39 -05:00
CommitQueue - > ResetAdding ( ) ;
2021-11-07 23:43:01 -05:00
CommitThread = AsyncThread ( [ this ] ( )
{
for ( ; ; )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FZenStoreWriter : : WaitingOnCooker ) ;
2022-05-18 14:49:11 -04:00
FZenCommitInfo Commit ;
2021-11-07 23:43:01 -05:00
if ( ! CommitQueue - > BlockAndDequeue ( Commit ) )
{
break ;
}
CommitPackageInternal ( MoveTemp ( Commit ) ) ;
}
} ) ;
}
2021-06-15 16:38:03 -04:00
}
void FZenStoreWriter : : EndCook ( )
{
2022-02-03 06:34:31 -05:00
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Flushing... " ) ) ;
CommitQueue - > WaitUntilEmpty ( ) ;
2021-11-07 23:43:01 -05:00
CommitQueue - > CompleteAdding ( ) ;
2021-06-15 16:38:03 -04:00
FCbPackage Pkg ;
FCbWriter PackageObj ;
PackageObj . BeginObject ( ) ;
PackageObj < < " key " < < " EndCook " ;
const bool bGenerateContainerHeader = true ;
CreateProjectMetaData ( Pkg , PackageObj , bGenerateContainerHeader ) ;
PackageObj . EndObject ( ) ;
FCbObject Obj = PackageObj . Save ( ) . AsObject ( ) ;
Pkg . SetObject ( Obj ) ;
TIoStatusOr < uint64 > Status = HttpClient - > EndBuildPass ( Pkg ) ;
UE_CLOG ( ! Status . IsOk ( ) , LogZenStoreWriter , Fatal , TEXT ( " Failed to append OpLog and end the build pass " ) ) ;
PackageStoreManifest . Save ( * ( MetadataDirectoryPath / TEXT ( " packagestore.manifest " ) ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Input: \t %d Packages " ) , PackageStoreOptimizer - > GetTotalPackageCount ( ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Output: \t %d Export bundles " ) , PackageStoreOptimizer - > GetTotalExportBundleCount ( ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Output: \t %d Export bundle entries " ) , PackageStoreOptimizer - > GetTotalExportBundleEntryCount ( ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Output: \t %d Internal export bundle arcs " ) , PackageStoreOptimizer - > GetTotalInternalBundleArcsCount ( ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Output: \t %d External export bundle arcs " ) , PackageStoreOptimizer - > GetTotalExternalBundleArcsCount ( ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Output: \t %d Public runtime script objects " ) , PackageStoreOptimizer - > GetTotalScriptObjectCount ( ) ) ;
}
2021-06-23 09:01:23 -04:00
void FZenStoreWriter : : BeginPackage ( const FBeginPackageInfo & Info )
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FPendingPackageState & State = AddPendingPackage ( Info . PackageName ) ;
State . PackageName = Info . PackageName ;
2021-06-15 16:38:03 -04:00
PackageStoreManifest . BeginPackage ( Info . PackageName ) ;
}
2021-09-08 07:04:39 -04:00
bool FZenStoreWriter : : IsReservedOplogKey ( FUtf8StringView Key )
{
int32 Index = Algo : : LowerBound ( ReservedOplogKeys , Key ,
[ ] ( const UTF8CHAR * Existing , FUtf8StringView Key )
{
return FUtf8StringView ( Existing ) . Compare ( Key , ESearchCase : : IgnoreCase ) < 0 ;
} ) ;
return Index ! = ReservedOplogKeys . Num ( ) & &
FUtf8StringView ( ReservedOplogKeys [ Index ] ) . Equals ( Key , ESearchCase : : IgnoreCase ) ;
}
2022-04-04 13:26:27 -04:00
void FZenStoreWriter : : CommitPackage ( FCommitPackageInfo & & Info )
2021-11-07 23:43:01 -05:00
{
2022-05-18 14:49:11 -04:00
if ( Info . Status = = ECommitStatus : : Canceled )
{
RemovePendingPackage ( Info . PackageName ) ;
return ;
}
2022-04-04 13:26:27 -04:00
UE : : SavePackageUtilities : : IncrementOutstandingAsyncWrites ( ) ;
2021-11-07 23:43:01 -05:00
2022-04-04 13:26:27 -04:00
// If we are computing hashes, we need to allocate where the hashes will go.
// Access to this is protected by the above IncrementOutstandingAsyncWrites.
2021-11-07 23:43:01 -05:00
if ( EnumHasAnyFlags ( Info . WriteOptions , EWriteOptions : : ComputeHash ) )
{
FPendingPackageState & ExistingState = GetPendingPackage ( Info . PackageName ) ;
2022-04-04 13:26:27 -04:00
ExistingState . PackageHashes = new FPackageHashes ( ) ;
2021-11-07 23:43:01 -05:00
2022-05-18 14:49:11 -04:00
if ( Info . Status = = ECommitStatus : : Success )
2022-04-04 13:26:27 -04:00
{
2022-04-26 17:36:49 -04:00
// Only record hashes for successful saves. A single package can be saved unsuccessfully multiple times
// during a cook if its rejected for being only referenced by editor-only references and we keep finding
// new references to it.
TRefCountPtr < FPackageHashes > & ExistingPackageHashes = AllPackageHashes . FindOrAdd ( Info . PackageName ) ;
// This looks weird but we've found the _TRefCountPtr_, not the FPackageHashes. When newly assigned
// it will be an empty pointer, which is what we want.
if ( ExistingPackageHashes . IsValid ( ) )
{
UE_LOG ( LogZenStoreWriter , Error , TEXT ( " FZenStoreWriter commiting the same package twice during a cook! (%s) " ) , * Info . PackageName . ToString ( ) ) ;
}
ExistingPackageHashes = ExistingState . PackageHashes ;
2022-04-04 13:26:27 -04:00
}
}
2021-11-07 23:43:01 -05:00
2022-05-18 14:49:11 -04:00
TUniquePtr < FPendingPackageState > PackageState = RemovePendingPackage ( Info . PackageName ) ;
FZenCommitInfo ZenCommitInfo { Forward < FCommitPackageInfo > ( Info ) , MoveTemp ( PackageState ) } ;
2021-11-07 23:43:01 -05:00
if ( FPlatformProcess : : SupportsMultithreading ( ) )
{
2022-05-18 14:49:11 -04:00
CommitQueue - > Enqueue ( MoveTemp ( ZenCommitInfo ) ) ;
2021-11-07 23:43:01 -05:00
}
else
{
2022-05-18 14:49:11 -04:00
CommitPackageInternal ( MoveTemp ( ZenCommitInfo ) ) ;
2021-11-07 23:43:01 -05:00
}
}
2022-05-18 14:49:11 -04:00
void FZenStoreWriter : : CommitPackageInternal ( FZenCommitInfo & & ZenCommitInfo )
2021-06-15 16:38:03 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FZenStoreWriter : : CommitPackage ) ;
2022-05-18 14:49:11 -04:00
FCommitPackageInfo & CommitInfo = ZenCommitInfo . CommitInfo ;
2021-11-07 23:43:01 -05:00
2022-05-18 14:49:11 -04:00
TUniquePtr < FPendingPackageState > PackageState = MoveTemp ( ZenCommitInfo . PackageState ) ;
2021-11-07 23:43:01 -05:00
checkf ( PackageState . IsValid ( ) , TEXT ( " Trying to commit non-pending package '%s' " ) , * CommitInfo . PackageName . ToString ( ) ) ;
2021-06-15 16:38:03 -04:00
IPackageStoreWriter : : FCommitEventArgs CommitEventArgs ;
2022-02-17 04:54:33 -05:00
CommitEventArgs . PlatformName = TargetPlatformFName ;
2021-11-07 23:43:01 -05:00
CommitEventArgs . PackageName = CommitInfo . PackageName ;
2021-06-15 16:38:03 -04:00
CommitEventArgs . EntryIndex = INDEX_NONE ;
2021-11-07 23:43:01 -05:00
const bool bComputeHash = EnumHasAnyFlags ( CommitInfo . WriteOptions , EWriteOptions : : ComputeHash ) ;
const bool bWritePackage = EnumHasAnyFlags ( CommitInfo . WriteOptions , EWriteOptions : : Write ) ;
2021-06-15 16:38:03 -04:00
2022-05-18 14:49:11 -04:00
if ( CommitInfo . Status = = ECommitStatus : : Success & & bWritePackage )
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FPackageDataEntry & PkgData = PackageState - > PackageData ;
checkf ( PkgData . IsValid , TEXT ( " CommitPackage called with bSucceeded but without first calling WritePackageData " ) )
checkf ( EnumHasAllFlags ( CommitInfo . WriteOptions , EWriteOptions : : Write ) , TEXT ( " Partial EWriteOptions::Write options are not yet implemented. " ) ) ;
checkf ( ! EnumHasAnyFlags ( CommitInfo . WriteOptions , EWriteOptions : : SaveForDiff ) , TEXT ( " -diffonly -savefordiff is not yet implemented. " ) ) ;
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FWriteScopeLock _ ( EntriesLock ) ;
CommitEventArgs . EntryIndex = PackageNameToIndex . FindOrAdd ( CommitInfo . PackageName , PackageStoreEntries . Num ( ) ) ;
2021-09-14 15:15:17 -04:00
if ( CommitEventArgs . EntryIndex = = PackageStoreEntries . Num ( ) )
{
PackageStoreEntries . Emplace ( ) ;
CookedPackagesInfo . Emplace ( ) ;
}
2021-11-07 23:43:01 -05:00
}
PackageStoreEntries [ CommitEventArgs . EntryIndex ] = PkgData . PackageStoreEntry ;
FMD5 PkgHashGen ;
FCbPackage OplogEntry ;
2022-04-04 13:26:27 -04:00
if ( bComputeHash )
{
PackageState - > PackageHashes - > ChunkHashes . Add ( PkgData . Info . ChunkId , PkgData . CompressedPayload . Get ( ) . GetRawHash ( ) ) ;
}
2021-11-07 23:43:01 -05:00
FCbAttachment PkgDataAttachment = FCbAttachment ( PkgData . CompressedPayload . Get ( ) ) ;
PkgHashGen . Update ( PkgDataAttachment . GetHash ( ) . GetBytes ( ) , sizeof ( FIoHash : : ByteArray ) ) ;
OplogEntry . AddAttachment ( PkgDataAttachment ) ;
// Commit attachments
FOplogCookInfo & CookInfo = CookedPackagesInfo [ CommitEventArgs . EntryIndex ] ;
CookInfo = FOplogCookInfo
{
FCookedPackageInfo
{
CommitInfo . PackageName ,
IoHashToMD5 ( PkgDataAttachment . GetHash ( ) ) ,
CommitInfo . PackageGuid ,
int64 ( PkgDataAttachment . AsCompressedBinary ( ) . GetRawSize ( ) )
2021-09-08 07:04:39 -04:00
}
2021-11-07 23:43:01 -05:00
} ;
2021-09-08 07:04:39 -04:00
2021-11-07 23:43:01 -05:00
CookInfo . bUpToDate = true ;
2021-06-23 09:01:23 -04:00
2021-11-07 23:43:01 -05:00
const int32 NumAttachments = CommitInfo . Attachments . Num ( ) ;
TArray < FCbAttachment , TInlineAllocator < 2 > > CbAttachments ;
if ( NumAttachments )
{
TArray < const FCommitAttachmentInfo * , TInlineAllocator < 2 > > SortedAttachments ;
SortedAttachments . Reserve ( NumAttachments ) ;
2021-06-23 09:01:23 -04:00
2021-11-07 23:43:01 -05:00
for ( const FCommitAttachmentInfo & AttachmentInfo : CommitInfo . Attachments )
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
SortedAttachments . Add ( & AttachmentInfo ) ;
}
2021-06-15 16:38:03 -04:00
2021-11-07 23:43:01 -05:00
SortedAttachments . Sort ( [ ] ( const FCommitAttachmentInfo & A , const FCommitAttachmentInfo & B )
{
return A . Key . Compare ( B . Key , ESearchCase : : IgnoreCase ) < 0 ;
} ) ;
CbAttachments . Reserve ( NumAttachments ) ;
CookInfo . Attachments . Reserve ( NumAttachments ) ;
for ( const FCommitAttachmentInfo * AttachmentInfo : SortedAttachments )
{
check ( ! IsReservedOplogKey ( AttachmentInfo - > Key ) ) ;
const FCbAttachment & CbAttachment = CbAttachments . Add_GetRef ( CreateAttachment ( AttachmentInfo - > Value . GetBuffer ( ) . ToShared ( ) ) ) ;
OplogEntry . AddAttachment ( CbAttachment ) ;
CookInfo . Attachments . Add ( FOplogCookInfo : : FAttachment
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
UE : : FZenStoreHttpClient : : FindOrAddAttachmentId ( AttachmentInfo - > Key ) , CbAttachment . GetHash ( )
} ) ;
2021-06-15 16:38:03 -04:00
}
}
2021-10-25 20:05:28 -04:00
2021-11-07 23:43:01 -05:00
// Create the oplog entry object
FCbWriter OplogEntryDesc ;
OplogEntryDesc . BeginObject ( ) ;
FString PackageNameKey = CommitInfo . PackageName . ToString ( ) ;
PackageNameKey . ToLowerInline ( ) ;
OplogEntryDesc < < " key " < < PackageNameKey ;
// NOTE: The package GUID and disk size are used for legacy iterative cooks when comparing asset registry package data
OplogEntryDesc . BeginObject ( " package " ) ;
OplogEntryDesc < < " id " < < PkgData . ChunkId ;
OplogEntryDesc < < " guid " < < CommitInfo . PackageGuid ;
OplogEntryDesc < < " data " < < PkgDataAttachment ;
OplogEntryDesc < < " disksize " < < PkgDataAttachment . AsCompressedBinary ( ) . GetRawSize ( ) ;
OplogEntryDesc . EndObject ( ) ;
OplogEntryDesc < < " packagestoreentry " < < PkgData . PackageStoreEntry ;
if ( PackageState - > BulkData . Num ( ) )
2021-10-25 20:05:28 -04:00
{
2021-11-07 23:43:01 -05:00
OplogEntryDesc . BeginArray ( " bulkdata " ) ;
for ( FBulkDataEntry & Bulk : PackageState - > BulkData )
{
2022-04-04 13:26:27 -04:00
if ( bComputeHash )
{
PackageState - > PackageHashes - > ChunkHashes . Add ( Bulk . Info . ChunkId , Bulk . CompressedPayload . Get ( ) . GetRawHash ( ) ) ;
}
2021-11-07 23:43:01 -05:00
FCbAttachment BulkAttachment ( Bulk . CompressedPayload . Get ( ) ) ;
PkgHashGen . Update ( BulkAttachment . GetHash ( ) . GetBytes ( ) , sizeof ( FIoHash : : ByteArray ) ) ;
OplogEntry . AddAttachment ( BulkAttachment ) ;
OplogEntryDesc . BeginObject ( ) ;
OplogEntryDesc < < " id " < < Bulk . ChunkId ;
OplogEntryDesc < < " type " < < LexToString ( Bulk . Info . BulkDataType ) ;
OplogEntryDesc < < " data " < < BulkAttachment ;
OplogEntryDesc . EndObject ( ) ;
}
OplogEntryDesc . EndArray ( ) ;
2021-10-25 20:05:28 -04:00
}
2021-11-07 23:43:01 -05:00
if ( PackageState - > FileData . Num ( ) )
{
OplogEntryDesc . BeginArray ( " files " ) ;
for ( FFileDataEntry & File : PackageState - > FileData )
{
2022-04-04 13:26:27 -04:00
if ( bComputeHash )
{
PackageState - > PackageHashes - > ChunkHashes . Add ( File . Info . ChunkId , File . CompressedPayload . Get ( ) . GetRawHash ( ) ) ;
}
2021-11-07 23:43:01 -05:00
FCbAttachment FileDataAttachment ( File . CompressedPayload . Get ( ) ) ;
PkgHashGen . Update ( FileDataAttachment . GetHash ( ) . GetBytes ( ) , sizeof ( FIoHash : : ByteArray ) ) ;
OplogEntry . AddAttachment ( FileDataAttachment ) ;
OplogEntryDesc . BeginObject ( ) ;
OplogEntryDesc < < " id " < < ToObjectId ( File . Info . ChunkId ) ;
OplogEntryDesc < < " data " < < FileDataAttachment ;
OplogEntryDesc < < " serverpath " < < File . ZenManifestServerPath ;
OplogEntryDesc < < " clientpath " < < File . ZenManifestClientPath ;
OplogEntryDesc . EndObject ( ) ;
CommitEventArgs . AdditionalFiles . Add ( FAdditionalFileInfo
{
CommitInfo . PackageName ,
File . ZenManifestClientPath ,
File . Info . ChunkId
} ) ;
}
OplogEntryDesc . EndArray ( ) ;
}
2022-04-04 13:26:27 -04:00
if ( bComputeHash )
{
PackageState - > PackageHashes - > PackageHash . Set ( PkgHashGen ) ;
}
2021-11-07 23:43:01 -05:00
for ( int32 Index = 0 ; Index < NumAttachments ; + + Index )
{
FCbAttachment & CbAttachment = CbAttachments [ Index ] ;
FOplogCookInfo : : FAttachment & CookInfoAttachment = CookInfo . Attachments [ Index ] ;
OplogEntryDesc < < CookInfoAttachment . Key < < CbAttachment ;
}
OplogEntryDesc . EndObject ( ) ;
OplogEntry . SetObject ( OplogEntryDesc . Save ( ) . AsObject ( ) ) ;
TIoStatusOr < uint64 > Status = HttpClient - > AppendOp ( MoveTemp ( OplogEntry ) ) ;
UE_CLOG ( ! Status . IsOk ( ) , LogZenStoreWriter , Error , TEXT ( " Failed to commit oplog entry '%s' to Zen " ) , * CommitInfo . PackageName . ToString ( ) ) ;
2021-06-15 16:38:03 -04:00
}
2022-05-18 14:49:11 -04:00
else if ( CommitInfo . Status = = ECommitStatus : : Success & & bComputeHash )
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FPackageDataEntry & PkgData = PackageState - > PackageData ;
checkf ( PkgData . IsValid , TEXT ( " CommitPackage called with bSucceeded but without first calling WritePackageData " ) ) ;
FMD5 PkgHashGen ;
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FCompressedBuffer Payload = PkgData . CompressedPayload . Get ( ) ;
FIoHash IoHash = Payload . GetRawHash ( ) ;
2022-04-04 13:26:27 -04:00
PackageState - > PackageHashes - > ChunkHashes . Add ( PkgData . Info . ChunkId , IoHash ) ;
2021-11-07 23:43:01 -05:00
PkgHashGen . Update ( IoHash . GetBytes ( ) , sizeof ( FIoHash : : ByteArray ) ) ;
}
for ( FBulkDataEntry & Bulk : PackageState - > BulkData )
{
FCompressedBuffer Payload = Bulk . CompressedPayload . Get ( ) ;
FIoHash IoHash = Payload . GetRawHash ( ) ;
2022-04-04 13:26:27 -04:00
PackageState - > PackageHashes - > ChunkHashes . Add ( Bulk . Info . ChunkId , IoHash ) ;
2021-11-07 23:43:01 -05:00
PkgHashGen . Update ( IoHash . GetBytes ( ) , sizeof ( FIoHash : : ByteArray ) ) ;
}
for ( FFileDataEntry & File : PackageState - > FileData )
{
FCompressedBuffer Payload = File . CompressedPayload . Get ( ) ;
FIoHash IoHash = Payload . GetRawHash ( ) ;
2022-04-04 13:26:27 -04:00
PackageState - > PackageHashes - > ChunkHashes . Add ( File . Info . ChunkId , IoHash ) ;
2021-11-07 23:43:01 -05:00
PkgHashGen . Update ( IoHash . GetBytes ( ) , sizeof ( FIoHash : : ByteArray ) ) ;
}
2022-04-04 13:26:27 -04:00
PackageState - > PackageHashes - > PackageHash . Set ( PkgHashGen ) ;
2021-11-07 23:43:01 -05:00
}
if ( bWritePackage )
2021-06-15 16:38:03 -04:00
{
BroadcastCommit ( CommitEventArgs ) ;
}
2021-11-07 23:43:01 -05:00
UE : : SavePackageUtilities : : DecrementOutstandingAsyncWrites ( ) ;
2021-10-25 20:05:28 -04:00
}
2021-09-14 15:15:17 -04:00
void FZenStoreWriter : : GetEntries ( TFunction < void ( TArrayView < const FPackageStoreEntryResource > , TArrayView < const FOplogCookInfo > ) > & & Callback )
2021-06-15 16:38:03 -04:00
{
2021-11-07 23:43:01 -05:00
FReadScopeLock _ ( EntriesLock ) ;
2021-09-14 15:15:17 -04:00
Callback ( PackageStoreEntries , CookedPackagesInfo ) ;
2021-06-15 16:38:03 -04:00
}
2021-09-17 09:32:48 -04:00
TUniquePtr < FAssetRegistryState > FZenStoreWriter : : LoadPreviousAssetRegistry ( )
2021-06-23 09:01:23 -04:00
{
2021-09-17 09:32:48 -04:00
// Load the previous asset registry to return to CookOnTheFlyServer, and set the packages enumerated in both *this and
// the returned asset registry to the intersection of the oplog and the previous asset registry;
// to report a package as already cooked we have to have the information from both sources.
FString PreviousAssetRegistryFile = FPaths : : Combine ( MetadataDirectoryPath , GetDevelopmentAssetRegistryFilename ( ) ) ;
FArrayReader SerializedAssetData ;
if ( ! IFileManager : : Get ( ) . FileExists ( * PreviousAssetRegistryFile ) | |
! FFileHelper : : LoadFileToArray ( SerializedAssetData , * PreviousAssetRegistryFile ) )
2021-09-08 07:04:39 -04:00
{
2021-09-17 09:32:48 -04:00
RemoveCookedPackages ( ) ;
return TUniquePtr < FAssetRegistryState > ( ) ;
2021-09-08 07:04:39 -04:00
}
2021-09-17 09:32:48 -04:00
TUniquePtr < FAssetRegistryState > PreviousState = MakeUnique < FAssetRegistryState > ( ) ;
PreviousState - > Load ( SerializedAssetData ) ;
TSet < FName > RemoveSet ;
const TMap < FName , const FAssetPackageData * > & PreviousStatePackages = PreviousState - > GetAssetPackageDataMap ( ) ;
for ( const TPair < FName , const FAssetPackageData * > & Pair : PreviousStatePackages )
{
FName PackageName = Pair . Key ;
if ( ! PackageNameToIndex . Find ( PackageName ) )
{
RemoveSet . Add ( PackageName ) ;
}
}
if ( RemoveSet . Num ( ) )
{
PreviousState - > PruneAssetData ( TSet < FName > ( ) , RemoveSet , FAssetRegistrySerializationOptions ( ) ) ;
}
TArray < FName > RemoveArray ;
for ( TPair < FName , int32 > & Pair : PackageNameToIndex )
{
FName PackageName = Pair . Key ;
if ( ! PreviousStatePackages . Find ( PackageName ) )
{
RemoveArray . Add ( PackageName ) ;
}
}
if ( RemoveArray . Num ( ) )
{
RemoveCookedPackages ( RemoveArray ) ;
}
return PreviousState ;
2021-06-23 09:01:23 -04:00
}
2021-09-08 07:04:39 -04:00
FCbObject FZenStoreWriter : : GetOplogAttachment ( FName PackageName , FUtf8StringView AttachmentKey )
2021-08-12 10:51:31 -04:00
{
const int32 * Idx = PackageNameToIndex . Find ( PackageName ) ;
if ( ! Idx )
{
return FCbObject ( ) ;
}
2021-09-08 07:04:39 -04:00
const UTF8CHAR * AttachmentId = UE : : FZenStoreHttpClient : : FindAttachmentId ( AttachmentKey ) ;
if ( ! AttachmentId )
{
return FCbObject ( ) ;
}
FUtf8StringView AttachmentIdView ( AttachmentId ) ;
const FOplogCookInfo & CookInfo = CookedPackagesInfo [ * Idx ] ;
int32 AttachmentIndex = Algo : : LowerBound ( CookInfo . Attachments , AttachmentIdView ,
[ ] ( const FOplogCookInfo : : FAttachment & Existing , FUtf8StringView AttachmentIdView )
{
return FUtf8StringView ( Existing . Key ) . Compare ( AttachmentIdView , ESearchCase : : IgnoreCase ) < 0 ;
} ) ;
if ( AttachmentIndex = = CookInfo . Attachments . Num ( ) )
{
return FCbObject ( ) ;
}
const FOplogCookInfo : : FAttachment & Existing = CookInfo . Attachments [ AttachmentIndex ] ;
if ( ! FUtf8StringView ( Existing . Key ) . Equals ( AttachmentIdView , ESearchCase : : IgnoreCase ) )
{
return FCbObject ( ) ;
}
TIoStatusOr < FIoBuffer > BufferResult = HttpClient - > ReadOpLogAttachment ( WriteToString < 48 > ( Existing . Hash ) ) ;
2021-08-12 10:51:31 -04:00
if ( ! BufferResult . IsOk ( ) )
{
return FCbObject ( ) ;
}
FIoBuffer Buffer = BufferResult . ValueOrDie ( ) ;
if ( Buffer . DataSize ( ) = = 0 )
{
return FCbObject ( ) ;
}
FSharedBuffer SharedBuffer = IoBufferToSharedBuffer ( Buffer ) ;
return FCbObject ( SharedBuffer ) ;
}
2021-06-23 09:01:23 -04:00
void FZenStoreWriter : : RemoveCookedPackages ( TArrayView < const FName > PackageNamesToRemove )
{
TSet < int32 > PackageIndicesToKeep ;
for ( int32 Idx = 0 , Num = PackageStoreEntries . Num ( ) ; Idx < Num ; + + Idx )
{
PackageIndicesToKeep . Add ( Idx ) ;
}
for ( const FName & PackageName : PackageNamesToRemove )
{
if ( const int32 * Idx = PackageNameToIndex . Find ( PackageName ) )
{
PackageIndicesToKeep . Remove ( * Idx ) ;
}
}
const int32 NumPackagesToKeep = PackageIndicesToKeep . Num ( ) ;
TArray < FPackageStoreEntryResource > PreviousPackageStoreEntries = MoveTemp ( PackageStoreEntries ) ;
2021-09-08 07:04:39 -04:00
TArray < FOplogCookInfo > PreviousCookedPackageInfo = MoveTemp ( CookedPackagesInfo ) ;
2021-08-20 10:57:45 -04:00
PackageNameToIndex . Empty ( ) ;
2021-06-23 09:01:23 -04:00
if ( NumPackagesToKeep > 0 )
{
PackageStoreEntries . Reserve ( NumPackagesToKeep ) ;
CookedPackagesInfo . Reserve ( NumPackagesToKeep ) ;
PackageNameToIndex . Reserve ( NumPackagesToKeep ) ;
int32 EntryIndex = 0 ;
for ( int32 Idx : PackageIndicesToKeep )
{
2021-09-08 07:04:39 -04:00
const FName PackageName = PreviousCookedPackageInfo [ Idx ] . CookInfo . PackageName ;
2021-06-23 09:01:23 -04:00
PackageStoreEntries . Add ( MoveTemp ( PreviousPackageStoreEntries [ Idx ] ) ) ;
CookedPackagesInfo . Add ( MoveTemp ( PreviousCookedPackageInfo [ Idx ] ) ) ;
PackageNameToIndex . Add ( PackageName , EntryIndex + + ) ;
}
}
}
2021-08-20 10:57:45 -04:00
void FZenStoreWriter : : RemoveCookedPackages ( )
{
PackageStoreEntries . Empty ( ) ;
CookedPackagesInfo . Empty ( ) ;
PackageNameToIndex . Empty ( ) ;
}
2021-09-14 15:15:17 -04:00
void FZenStoreWriter : : MarkPackagesUpToDate ( TArrayView < const FName > UpToDatePackages )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FZenStoreWriter : : MarkPackagesUpToDate ) ;
IPackageStoreWriter : : FMarkUpToDateEventArgs MarkUpToDateEventArgs ;
MarkUpToDateEventArgs . PackageIndexes . Reserve ( UpToDatePackages . Num ( ) ) ;
{
2021-11-07 23:43:01 -05:00
FWriteScopeLock _ ( EntriesLock ) ;
2021-09-14 15:15:17 -04:00
for ( FName PackageName : UpToDatePackages )
{
int32 * Index = PackageNameToIndex . Find ( PackageName ) ;
if ( ! Index )
{
2021-09-17 09:32:48 -04:00
if ( ! FPackageName : : IsScriptPackage ( WriteToString < 128 > ( PackageName ) ) )
{
UE_LOG ( LogZenStoreWriter , Warning , TEXT ( " MarkPackagesUpToDate called with package %s that is not in the oplog. " ) ,
* PackageName . ToString ( ) ) ;
}
2021-09-14 15:15:17 -04:00
continue ;
}
MarkUpToDateEventArgs . PackageIndexes . Add ( * Index ) ;
CookedPackagesInfo [ * Index ] . bUpToDate = true ;
}
}
if ( MarkUpToDateEventArgs . PackageIndexes . Num ( ) )
{
BroadcastMarkUpToDate ( MarkUpToDateEventArgs ) ;
}
}
2021-06-15 16:38:03 -04:00
void FZenStoreWriter : : CreateProjectMetaData ( FCbPackage & Pkg , FCbWriter & PackageObj , bool bGenerateContainerHeader )
{
// File Manifest
{
2021-06-23 09:01:23 -04:00
// Only append new file entries to the Oplog
int32 NumEntries = ZenFileSystemManifest - > NumEntries ( ) ;
const int32 NumNewEntries = ZenFileSystemManifest - > Generate ( ) ;
2021-06-15 16:38:03 -04:00
2021-06-23 09:01:23 -04:00
if ( NumNewEntries > 0 )
2021-06-15 16:38:03 -04:00
{
2021-06-23 09:01:23 -04:00
TArrayView < FZenFileSystemManifest : : FManifestEntry const > Entries = ZenFileSystemManifest - > ManifestEntries ( ) ;
TArrayView < FZenFileSystemManifest : : FManifestEntry const > NewEntries = Entries . Slice ( NumEntries , NumNewEntries ) ;
2021-06-15 16:38:03 -04:00
PackageObj . BeginArray ( " files " ) ;
2021-06-23 09:01:23 -04:00
for ( const FZenFileSystemManifest : : FManifestEntry & NewEntry : NewEntries )
2021-06-15 16:38:03 -04:00
{
2021-06-23 09:01:23 -04:00
FCbObjectId FileOid = ToObjectId ( NewEntry . FileChunkId ) ;
2021-06-15 16:38:03 -04:00
PackageObj . BeginObject ( ) ;
PackageObj < < " id " < < FileOid ;
PackageObj < < " data " < < FIoHash : : Zero ;
2021-06-23 09:01:23 -04:00
PackageObj < < " serverpath " < < NewEntry . ServerPath ;
PackageObj < < " clientpath " < < NewEntry . ClientPath ;
2021-06-15 16:38:03 -04:00
PackageObj . EndObject ( ) ;
}
2021-06-23 09:01:23 -04:00
PackageObj . EndArray ( ) ;
2021-06-15 16:38:03 -04:00
}
2021-06-23 09:01:23 -04:00
FString ManifestPath = FPaths : : Combine ( MetadataDirectoryPath , TEXT ( " zenfs.manifest " ) ) ;
UE_LOG ( LogZenStoreWriter , Display , TEXT ( " Saving Zen filesystem manifest '%s' " ) , * ManifestPath ) ;
ZenFileSystemManifest - > Save ( * ManifestPath ) ;
2021-06-15 16:38:03 -04:00
}
// Metadata section
{
PackageObj . BeginArray ( " meta " ) ;
// Summarize Script Objects
FIoBuffer ScriptObjectsBuffer = PackageStoreOptimizer - > CreateScriptObjectsBuffer ( ) ;
FCbObjectId ScriptOid = ToObjectId ( CreateIoChunkId ( 0 , 0 , EIoChunkType : : ScriptObjects ) ) ;
2021-10-25 20:05:28 -04:00
FCbAttachment ScriptAttachment = CreateAttachment ( ScriptObjectsBuffer ) ;
2021-06-15 16:38:03 -04:00
Pkg . AddAttachment ( ScriptAttachment ) ;
PackageObj . BeginObject ( ) ;
PackageObj < < " id " < < ScriptOid ;
PackageObj < < " name " < < " ScriptObjects " ;
PackageObj < < " data " < < ScriptAttachment ;
PackageObj . EndObject ( ) ;
// Generate Container Header
if ( bGenerateContainerHeader )
{
FCbObjectId HeaderOid = ToObjectId ( CreateIoChunkId ( ContainerId . Value ( ) , 0 , EIoChunkType : : ContainerHeader ) ) ;
FIoBuffer HeaderBuffer ;
{
2022-04-25 07:37:07 -04:00
FIoContainerHeader Header = PackageStoreOptimizer - > CreateContainerHeader ( ContainerId , PackageStoreEntries , FPackageStoreOptimizer : : IncludeAllSegments ) ;
2021-06-15 16:38:03 -04:00
FLargeMemoryWriter HeaderAr ( 0 , true ) ;
HeaderAr < < Header ;
int64 DataSize = HeaderAr . TotalSize ( ) ;
HeaderBuffer = FIoBuffer ( FIoBuffer : : AssumeOwnership , HeaderAr . ReleaseOwnership ( ) , DataSize ) ;
}
2021-10-25 20:05:28 -04:00
FCbAttachment HeaderAttachment = CreateAttachment ( HeaderBuffer ) ;
2021-06-15 16:38:03 -04:00
Pkg . AddAttachment ( HeaderAttachment ) ;
PackageObj . BeginObject ( ) ;
PackageObj < < " id " < < HeaderOid ;
PackageObj < < " name " < < " ContainerHeader " ;
PackageObj < < " data " < < HeaderAttachment ;
PackageObj . EndObject ( ) ;
}
PackageObj . EndArray ( ) ; // End of Meta array
}
}
void FZenStoreWriter : : BroadcastCommit ( IPackageStoreWriter : : FCommitEventArgs & EventArgs )
{
FScopeLock CommitEventLock ( & CommitEventCriticalSection ) ;
if ( CommitEvent . IsBound ( ) )
{
2021-11-07 23:43:01 -05:00
FReadScopeLock _ ( EntriesLock ) ;
2021-06-15 16:38:03 -04:00
EventArgs . Entries = PackageStoreEntries ;
CommitEvent . Broadcast ( EventArgs ) ;
}
}
2021-09-14 15:15:17 -04:00
void FZenStoreWriter : : BroadcastMarkUpToDate ( IPackageStoreWriter : : FMarkUpToDateEventArgs & EventArgs )
{
FScopeLock CommitEventLock ( & CommitEventCriticalSection ) ;
if ( MarkUpToDateEvent . IsBound ( ) )
{
2021-11-07 23:43:01 -05:00
FReadScopeLock _ ( EntriesLock ) ;
2022-02-17 04:54:33 -05:00
EventArgs . PlatformName = TargetPlatformFName ;
2021-09-14 15:15:17 -04:00
EventArgs . Entries = PackageStoreEntries ;
EventArgs . CookInfos = CookedPackagesInfo ;
MarkUpToDateEvent . Broadcast ( EventArgs ) ;
}
}
2021-10-25 20:05:28 -04:00
FCbAttachment FZenStoreWriter : : CreateAttachment ( FSharedBuffer AttachmentData )
{
check ( AttachmentData . GetSize ( ) > 0 ) ;
FCompressedBuffer CompressedBuffer = FCompressedBuffer : : Compress ( AttachmentData , Compressor , CompressionLevel ) ;
check ( ! CompressedBuffer . IsNull ( ) ) ;
return FCbAttachment ( CompressedBuffer ) ;
}
FCbAttachment FZenStoreWriter : : CreateAttachment ( FIoBuffer AttachmentData )
{
return CreateAttachment ( IoBufferToSharedBuffer ( AttachmentData ) ) ;
}