Files
UnrealEngine/Engine/Source/Runtime/Online/BuildPatchServices/Private/Installer/ChunkReferenceTracker.h
2025-05-18 13:04:45 +08:00

273 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "BuildPatchManifest.h"
#include "IBuildManifestSet.h"
namespace BuildPatchServices
{
/**
* An interface for tracking references to chunks used throughout an installation. It is used to share across systems the
* chunks that are still required and when.
*/
class IChunkReferenceTracker
{
public:
enum class ESortDirection : uint8
{
Ascending = 0,
Descending
};
public:
virtual ~IChunkReferenceTracker() {}
/**
* Gets a set of all chunks referenced by the installation this tracker refers to.
* This returns the _remaining_ referenced chunks!
* @return set of GUID containing every chunk used.
*/
virtual TSet<FGuid> GetReferencedChunks() const = 0;
/**
* Gets the number of times a specific chunk is still referenced for the associated installation.
* @param ChunkId The id for the chunk in question.
* @return the number of references remaining.
*/
virtual int32 GetReferenceCount(const FGuid& ChunkId) const = 0;
/**
* Sorts a given array of chunk ids by the order in which they are required for the installation.
* @param ChunkList The array to be sorted.
* @param Direction The direction of sort. Ascending places soonest required chunk first.
*/
virtual void SortByUseOrder(TArray<FGuid>& ChunkList, ESortDirection Direction) const = 0;
/**
* Find the next X chunk references that match the provided predicate.
* @param Count The number of chunk entries that are desired.
* @param SelectPredicate The predicate used to select each chunk.
* @return an array of unique chunk id entries, in the order in which they are required.
*/
virtual TArray<FGuid> GetNextReferences(int32 Count, const TFunction<bool(const FGuid&)>& SelectPredicate) const = 0;
/**
* Select from the next X chunk references, entries that match the provided predicate.
* @param Count The number of chunk entries to search through.
* @param SelectPredicate The predicate used to select each chunk.
* @return an array of unique chunk id entries, in the order in which they are required.
*/
virtual TArray<FGuid> SelectFromNextReferences(int32 Count, const TFunction<bool(const FGuid&)>& SelectPredicate) const = 0;
/**
* Poorly named - Should be named "DoneWithChunk". The expectation is that we finish with chunks in the expected
* use order.
*
* Pop the top reference from the tracker, indicating that operation has been performed.
* It is not valid to pop anything but the top guid, so it must be provided for verification of behavior.
* @param ChunkId The id of the top chunk, this is used to verify behavior.
* @return true if the correct guid was provided and the reference was popped, false if the wrong guid
* was provided and thus no change was made.
*/
virtual bool PopReference(const FGuid& ChunkId) = 0;
// Return how many chunks are left to process.
virtual int32 GetRemainingChunkCount() const = 0;
// Return the ordered list we are consuming.
// copies the _remaining_ items!
virtual void CopyOutOrderedUseList(TArray<FGuid>& OutUseList) const = 0;
// Returns the next usage index in _advancing order_ for the chunkid, or -1 if it won't
// be used again.
virtual int32 GetNextUsageForChunk(const FGuid& ChunkId, int32& OutLastUsageIndex) const = 0;
virtual int32 GetCurrentUsageIndex() const = 0;
};
/**
* A factory for creating an IChunkReferenceTracker instance.
*/
class FChunkReferenceTrackerFactory
{
public:
/**
* This implementation takes the install manifest and generates the internal data and chunk reference tracking based
* off of a set of files that will be constructed.
* @param InstallManifest The install manifest to enumerate references from.
* @param FilesToConstruct The set of files to be installed, other files will not be considered.
* @return the new IChunkReferenceTracker instance created.
*/
static IChunkReferenceTracker* Create(const IBuildManifestSet* Manifest, const TSet<FString>& FilesToConstruct);
/**
* This implementation takes custom chunk references to track. The array should be every chunk reference, including duplicates, in order of use.
* See namespace CustomChunkReferencesHelpers for common setup examples to use.
* @param CustomChunkReferences The custom chunk references to track.
* @return the new IChunkReferenceTracker instance created.
*/
static IChunkReferenceTracker* Create(TArray<FGuid> CustomChunkReferences);
};
/**
* Helpers for creating a CustomChunkReferences array for use with the equivalent FChunkReferenceTrackerFactory.
*/
namespace CustomChunkReferencesHelpers
{
/**
* This implementation takes the install manifest and generates the CustomChunkReferences needed for a chunk reference tracker based
* on caching data and so using each chunk once in the order that would be required to install the build.
* @param InstallManifest The install manifest to enumerate references from.
* @return the chunk use references for FChunkReferenceTrackerFactory::Create.
*/
FORCEINLINE TArray<FGuid> OrderedUniqueReferences(const FBuildPatchAppManifestRef& InstallManifest)
{
TArray<FGuid> ChunkReferences;
// Create our full list of chunks, no dupes, just one reference per chunk in the correct order.
TArray<FString> AllFiles;
TSet<FGuid> AllChunks;
InstallManifest->GetFileList(AllFiles);
for (const FString& File : AllFiles)
{
const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File);
if (NewFileManifest != nullptr)
{
for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts)
{
bool bWasAlreadyInSet = false;
AllChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet);
if (!bWasAlreadyInSet)
{
ChunkReferences.Add(ChunkPart.Guid);
}
}
}
}
return ChunkReferences;
}
/**
* This implementation takes a new install manifest and a current manifest. It generates the CustomChunkReferences needed for a chunk reference tracker based
* on caching data for a patch only, and so using the chunks in InstallManifest, which are not in CurrentManifest, once each in the order that they
* would be required to patch the build.
* @param InstallManifest The install manifest to enumerate chunk references from.
* @param CurrentManifest The current manifest to exclude chunk references from.
* @return the chunk use references for FChunkReferenceTrackerFactory::Create.
*/
FORCEINLINE TArray<FGuid> OrderedUniquePatchReferences(const FBuildPatchAppManifestRef& InstallManifest, const FBuildPatchAppManifestRef& CurrentManifest)
{
TArray<FGuid> ChunkReferences;
// Create our list of chunks, no dupes, just one reference per chunk which appears only in InstallManifest, and in the correct order of use.
TArray<FString> AllFiles;
TSet<FGuid> OldChunks;
TSet<FGuid> NewChunks;
CurrentManifest->GetDataList(OldChunks);
InstallManifest->GetFileList(AllFiles);
for (const FString& File : AllFiles)
{
const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File);
if (NewFileManifest != nullptr)
{
for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts)
{
const bool bIsNewChunk = !OldChunks.Contains(ChunkPart.Guid);
if (bIsNewChunk)
{
bool bWasAlreadyInSet = false;
NewChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet);
if (!bWasAlreadyInSet)
{
ChunkReferences.Add(ChunkPart.Guid);
}
}
}
}
}
return ChunkReferences;
}
/**
* This implementation takes the install manifest and a tagset. It generates the CustomChunkReferences needed for a chunk reference tracker based
* on caching data and so using each chunk once in the order that would be required to install the build when using the same tagset provided.
* @param InstallManifest The install manifest to enumerate references from.
* @param InstallTagSet The tagset that would be used with install manifest, this will filter down required file list and thus required chunk list.
* @return the chunk use references for FChunkReferenceTrackerFactory::Create.
*/
FORCEINLINE TArray<FGuid> OrderedUniqueReferencesTagged(const FBuildPatchAppManifestRef& InstallManifest, const TSet<FString>& InstallTagSet)
{
TArray<FGuid> ChunkReferences;
// Create our full list of chunks, no dupes, just one reference per chunk in the correct order.
TArray<FString> TaggedFiles;
TSet<FGuid> TaggedChunks;
InstallManifest->GetTaggedFileList(InstallTagSet, TaggedFiles);
for (const FString& File : TaggedFiles)
{
const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File);
if (NewFileManifest != nullptr)
{
for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts)
{
bool bWasAlreadyInSet = false;
TaggedChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet);
if (!bWasAlreadyInSet)
{
ChunkReferences.Add(ChunkPart.Guid);
}
}
}
}
return ChunkReferences;
}
/**
* This implementation takes a new install manifest, a current manifest, and a tagset for each. It generates the CustomChunkReferences needed for a chunk reference tracker based
* on caching data for a patch only, and so using the chunks in InstallManifest, which are not in CurrentManifest, once each in the order that would be required
* to patch the build when using the tagsets provided.
* @param InstallManifest The install manifest to enumerate chunk references from.
* @param InstallTagSet The tagset that would be used with install manifest, this will filter down required file list and thus required chunk list.
* @param CurrentManifest The current manifest if considering an update, which reduces the number of chunks required.
* @param CurrentTagSet The tagset filtering files from CurrentManifest, so that chunks would not be ignored for files not present on disk. This would often be the same as InstallTagSet unless
* InstallManifest changed the file tag names, or you are calling for purpose of adding/removing tags.
* @return the chunk use references for FChunkReferenceTrackerFactory::Create.
*/
FORCEINLINE TArray<FGuid> OrderedUniquePatchReferencesTagged(const FBuildPatchAppManifestRef& InstallManifest, const TSet<FString>& InstallTagSet, const FBuildPatchAppManifestRef& CurrentManifest, const TSet<FString>& CurrentTagSet)
{
// Enumerate what is available in the current build.
TSet<FString> FilesInstalled;
TSet<FGuid> ChunksRequired;
TSet<FGuid> ChunksInstalled;
CurrentManifest->GetTaggedFileList(CurrentTagSet, FilesInstalled);
CurrentManifest->GetChunksRequiredForFiles(FilesInstalled, ChunksRequired);
CurrentManifest->EnumerateProducibleChunks(CurrentTagSet, ChunksRequired, ChunksInstalled);
TArray<FGuid> ChunkReferences;
// Create our list of chunks, no dupes, just one reference per chunk which appears only in InstallManifest, and in the correct order of use.
TArray<FString> TaggedFiles;
TSet<FGuid> TaggedNewChunks;
InstallManifest->GetTaggedFileList(InstallTagSet, TaggedFiles);
for (const FString& File : TaggedFiles)
{
const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File);
if (NewFileManifest != nullptr)
{
for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts)
{
const bool bIsNewChunk = !ChunksInstalled.Contains(ChunkPart.Guid);
if (bIsNewChunk)
{
bool bWasAlreadyInSet = false;
TaggedNewChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet);
if (!bWasAlreadyInSet)
{
ChunkReferences.Add(ChunkPart.Guid);
}
}
}
}
}
return ChunkReferences;
}
}
}