Files
UnrealEngine/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBuildWorkerRegistry.cpp
2025-05-18 13:04:45 +08:00

275 lines
9.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DerivedDataBuildWorkerRegistry.h"
#include "Algo/Find.h"
#include "Containers/SharedString.h"
#include "Containers/StringView.h"
#include "Containers/UnrealString.h"
#include "DerivedDataBuildKey.h"
#include "DerivedDataBuildPrivate.h"
#include "DerivedDataBuildWorker.h"
#include "Features/IModularFeatures.h"
#include "HAL/CriticalSection.h"
#include "IO/IoHash.h"
#include "Misc/Guid.h"
#include "Misc/ScopeRWLock.h"
#include "Templates/Function.h"
#include "Templates/Tuple.h"
namespace UE::DerivedData::Private
{
class FBuildWorkerInternal final : public FBuildWorker, public FBuildWorkerBuilder
{
public:
inline explicit FBuildWorkerInternal(IBuildWorkerFactory* InFactory)
: Factory(InFactory)
{
}
void Build();
inline FStringView GetName() const final { return WorkerName; }
inline FStringView GetPath() const final { return WorkerPath; }
inline FStringView GetHostPlatform() const final { return HostPlatform; }
inline FGuid GetBuildSystemVersion() const final { return BuildSystemVersion; }
void FindFileData(TConstArrayView<FIoHash> RawHashes, IRequestOwner& Owner, FOnBuildWorkerFileDataComplete&& OnComplete) const final;
void IterateFunctions(TFunctionRef<void (FUtf8StringView Name, const FGuid& Version)> Visitor) const final;
void IterateFiles(TFunctionRef<void (FStringView Path, const FIoHash& RawHash, uint64 RawSize)> Visitor) const final;
void IterateExecutables(TFunctionRef<void (FStringView Path, const FIoHash& RawHash, uint64 RawSize)> Visitor) const final;
void IterateEnvironment(TFunctionRef<void (FStringView Name, FStringView Value)> Visitor) const final;
private:
inline void SetName(FStringView Name) final { WorkerName = Name; }
inline void SetPath(FStringView Path) final { WorkerPath = Path; }
inline void SetHostPlatform(FStringView Name) final { HostPlatform = Name; }
inline void SetBuildSystemVersion(const FGuid& Version) final { BuildSystemVersion = Version; }
void AddFunction(FUtf8StringView Name, const FGuid& Version) final;
void AddFile(FStringView Path, const FIoHash& RawHash, uint64 RawSize) final;
void AddExecutable(FStringView Path, const FIoHash& RawHash, uint64 RawSize) final;
void SetEnvironment(FStringView Name, FStringView Value) final;
private:
FString WorkerName;
FString WorkerPath;
FString HostPlatform;
FGuid BuildSystemVersion;
TArray<TTuple<FUtf8SharedString, FGuid>> Functions;
TArray<TTuple<FString, FIoHash, uint64>> Files;
TArray<TTuple<FString, FIoHash, uint64>> Executables;
TArray<TTuple<FString, FString>> Environment;
IBuildWorkerFactory* Factory;
};
void FBuildWorkerInternal::Build()
{
Functions.Sort();
Files.Sort();
Executables.Sort();
Environment.Sort();
}
void FBuildWorkerInternal::FindFileData(TConstArrayView<FIoHash> RawHashes, IRequestOwner& Owner, FOnBuildWorkerFileDataComplete&& OnComplete) const
{
return Factory->FindFileData(RawHashes, Owner, MoveTemp(OnComplete));
}
void FBuildWorkerInternal::IterateFunctions(TFunctionRef<void (FUtf8StringView Name, const FGuid& Version)> Visitor) const
{
for (const TTuple<FUtf8SharedString, FGuid>& Function : Functions)
{
Function.ApplyAfter(Visitor);
}
}
void FBuildWorkerInternal::IterateFiles(TFunctionRef<void (FStringView Path, const FIoHash& RawHash, uint64 RawSize)> Visitor) const
{
for (const TTuple<FString, FIoHash, uint64>& File : Files)
{
File.ApplyAfter(Visitor);
}
}
void FBuildWorkerInternal::IterateExecutables(TFunctionRef<void (FStringView Path, const FIoHash& RawHash, uint64 RawSize)> Visitor) const
{
for (const TTuple<FString, FIoHash, uint64>& Executable : Executables)
{
Executable.ApplyAfter(Visitor);
}
}
void FBuildWorkerInternal::IterateEnvironment(TFunctionRef<void (FStringView Name, FStringView Value)> Visitor) const
{
for (const TTuple<FString, FString>& Variable : Environment)
{
Variable.ApplyAfter(Visitor);
}
}
void FBuildWorkerInternal::AddFunction(FUtf8StringView Name, const FGuid& Version)
{
UE_CLOG(!Version.IsValid(), LogDerivedDataBuild, Error,
TEXT("Version of zero is not allowed in build function with the name %s in build worker '%s'."),
*WriteToString<32>(Name), *WorkerName);
Functions.Emplace(Name, Version);
}
void FBuildWorkerInternal::AddFile(FStringView Path, const FIoHash& RawHash, uint64 RawSize)
{
Files.Emplace(Path, RawHash, RawSize);
}
void FBuildWorkerInternal::AddExecutable(FStringView Path, const FIoHash& RawHash, uint64 RawSize)
{
Executables.Emplace(Path, RawHash, RawSize);
}
void FBuildWorkerInternal::SetEnvironment(FStringView Name, FStringView Value)
{
Environment.Emplace(Name, Value);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FBuildWorkerRegistry final : public IBuildWorkerRegistry
{
public:
FBuildWorkerRegistry();
~FBuildWorkerRegistry();
FBuildWorker* FindWorker(
const FUtf8SharedString& Function,
const FGuid& FunctionVersion,
const FGuid& BuildSystemVersion,
IBuildWorkerExecutor*& OutWorkerExecutor) const final;
private:
void OnModularFeatureRegistered(const FName& Type, IModularFeature* ModularFeature);
void OnModularFeatureUnregistered(const FName& Type, IModularFeature* ModularFeature);
void AddWorker(IBuildWorkerFactory* Factory);
void RemoveWorker(IBuildWorkerFactory* Factory);
private:
mutable FRWLock Lock;
IBuildWorkerExecutor* Executor = nullptr;
TMap<IBuildWorkerFactory*, TUniquePtr<FBuildWorker>> Workers;
TMultiMap<TTuple<FUtf8SharedString, FGuid>, FBuildWorker*> Functions;
};
FBuildWorkerRegistry::FBuildWorkerRegistry()
{
IModularFeatures& ModularFeatures = IModularFeatures::Get();
if (ModularFeatures.IsModularFeatureAvailable(IBuildWorkerExecutor::FeatureName))
{
Executor = &ModularFeatures.GetModularFeature<IBuildWorkerExecutor>(IBuildWorkerExecutor::FeatureName);
}
for (IBuildWorkerFactory* Worker : ModularFeatures.GetModularFeatureImplementations<IBuildWorkerFactory>(IBuildWorkerFactory::FeatureName))
{
AddWorker(Worker);
}
ModularFeatures.OnModularFeatureRegistered().AddRaw(this, &FBuildWorkerRegistry::OnModularFeatureRegistered);
ModularFeatures.OnModularFeatureUnregistered().AddRaw(this, &FBuildWorkerRegistry::OnModularFeatureUnregistered);
}
FBuildWorkerRegistry::~FBuildWorkerRegistry()
{
IModularFeatures& ModularFeatures = IModularFeatures::Get();
ModularFeatures.OnModularFeatureUnregistered().RemoveAll(this);
ModularFeatures.OnModularFeatureRegistered().RemoveAll(this);
}
void FBuildWorkerRegistry::OnModularFeatureRegistered(const FName& Type, IModularFeature* ModularFeature)
{
if (!Executor && Type == IBuildWorkerExecutor::FeatureName)
{
FWriteScopeLock WriteLock(Lock);
Executor = static_cast<IBuildWorkerExecutor*>(ModularFeature);
}
else if (Type == IBuildWorkerFactory::FeatureName)
{
AddWorker(static_cast<IBuildWorkerFactory*>(ModularFeature));
}
}
void FBuildWorkerRegistry::OnModularFeatureUnregistered(const FName& Type, IModularFeature* ModularFeature)
{
if (Executor == ModularFeature && Type == IBuildWorkerExecutor::FeatureName)
{
IModularFeature* NextExecutor = nullptr;
IModularFeatures& ModularFeatures = IModularFeatures::Get();
if (ModularFeatures.IsModularFeatureAvailable(IBuildWorkerExecutor::FeatureName))
{
NextExecutor = &ModularFeatures.GetModularFeature<IBuildWorkerExecutor>(IBuildWorkerExecutor::FeatureName);
}
FWriteScopeLock WriteLock(Lock);
Executor = static_cast<IBuildWorkerExecutor*>(NextExecutor);
}
else if (Type == IBuildWorkerFactory::FeatureName)
{
RemoveWorker(static_cast<IBuildWorkerFactory*>(ModularFeature));
}
}
void FBuildWorkerRegistry::AddWorker(IBuildWorkerFactory* Factory)
{
TUniquePtr<FBuildWorkerInternal> Worker = MakeUnique<FBuildWorkerInternal>(Factory);
Factory->Build(*Worker);
Worker->Build();
FWriteScopeLock WriteLock(Lock);
Worker->IterateFunctions([this, Worker = Worker.Get()](FUtf8StringView Name, const FGuid& Version)
{
Functions.Emplace(MakeTuple(FUtf8SharedString(Name), Version), Worker);
});
Workers.Emplace(Factory, MoveTemp(Worker));
}
void FBuildWorkerRegistry::RemoveWorker(IBuildWorkerFactory* Factory)
{
FWriteScopeLock WriteLock(Lock);
TUniquePtr<FBuildWorker>& Worker = Workers.FindChecked(Factory);
Worker->IterateFunctions([this, Worker = Worker.Get()](FUtf8StringView Name, const FGuid& Version)
{
Functions.Remove(MakeTuple(FUtf8SharedString(Name), Version), Worker);
});
Workers.Remove(Factory);
}
FBuildWorker* FBuildWorkerRegistry::FindWorker(
const FUtf8SharedString& Function,
const FGuid& FunctionVersion,
const FGuid& BuildSystemVersion,
IBuildWorkerExecutor*& OutWorkerExecutor) const
{
FReadScopeLock ReadLock(Lock);
if (Executor)
{
TConstArrayView<FStringView> ExecutorHostPlatforms = Executor->GetHostPlatforms();
TArray<FBuildWorker*, TInlineAllocator<8>> FunctionWorkers;
Functions.MultiFind(MakeTuple(Function, FunctionVersion), FunctionWorkers);
for (FBuildWorker* Worker : FunctionWorkers)
{
if (Worker->GetBuildSystemVersion() == BuildSystemVersion &&
Algo::Find(ExecutorHostPlatforms, Worker->GetHostPlatform()))
{
OutWorkerExecutor = Executor;
return Worker;
}
}
}
OutWorkerExecutor = nullptr;
return nullptr;
}
IBuildWorkerRegistry* CreateBuildWorkerRegistry()
{
return new FBuildWorkerRegistry();
}
} // UE::DerivedData::Private