// Copyright Epic Games, Inc. All Rights Reserved. using System; using EpicGames.UBA.Impl; namespace EpicGames.UBA { /// /// Information needed to create a session server /// /// Root directory to store content addressable data /// Path to a trace file that records the build /// If the custom allocator should be disabled /// If the visualizer should be launched /// If the content addressable storage should be reset /// If intermediate/output files should be written to disk /// More detailed trace information /// Wait for memory before starting new processes /// Kill processes when close to run out of memory /// Store .obj files compressed on disk public readonly struct SessionServerCreateInfo(string rootDirectory, string traceOutputFile, bool disableCustomAllocator, bool launchVisualizer, bool resetCas, bool writeToDisk, bool detailedTrace, bool allowWaitOnMem, bool allowKillOnMem, bool storeObjFilesCompressed) { /// /// Root directory to store content addressable data /// public string RootDirectory { get; } = rootDirectory; /// /// Path to a trace file that records the build /// public string TraceOutputFile { get; } = traceOutputFile; /// /// If the custom allocator should be disabled /// public bool DisableCustomAllocator { get; } = disableCustomAllocator; /// /// If the visualizer should be launched /// public bool LaunchVisualizer { get; } = launchVisualizer; /// /// If the content addressable storage should be reset /// public bool ResetCas { get; } = resetCas; /// /// If intermediate/output files should be written to disk /// public bool WriteToDisk { get; } = writeToDisk; /// /// More detailed trace information /// public bool DetailedTrace { get; } = detailedTrace; /// /// Wait for memory before starting new processes /// public bool AllowWaitOnMem { get; } = allowWaitOnMem; /// /// Kill processes when close to run out of memory /// public bool AllowKillOnMem { get; } = allowKillOnMem; /// /// Store .obj files compressed on disk /// public bool StoreObjFilesCompressed { get; } = storeObjFilesCompressed; } /// /// Base interface for session server create info /// public interface ISessionServerCreateInfo : IBaseInterface { /// /// Create a ISessionServerCreateInfo object /// /// The storage server /// The client /// The logger /// The session create info /// The ISessionServerCreateInfo public static ISessionServerCreateInfo CreateSessionServerCreateInfo(IStorageServer storage, IServer client, ILogger logger, SessionServerCreateInfo info) { return new SessionServerCreateInfoImpl(storage, client, logger, info); } } /// /// Event args for remote process slot available event /// /// Is true if the available remote process slot is on a cross architecture machine public class RemoteProcessSlotAvailableEventArgs(bool isCrossArchitecture) : EventArgs { /// /// Is true if the available remote process slot is on a cross architecture machine /// public bool IsCrossArchitecture { get; } = isCrossArchitecture; } /// /// Event args for remote process returned event /// /// The process being returned public class RemoteProcessReturnedEventArgs(IProcess process) : EventArgs { /// /// The remote process that was returned /// public IProcess Process { get; } = process; } /// /// Base interface for a session server instance /// public interface ISessionServer : IBaseInterface { /// /// Degeate for remote process slot available events /// /// The sender object /// The event args public delegate void RemoteProcessSlotAvailableEventHandler(object sender, RemoteProcessSlotAvailableEventArgs e); /// /// Degeate for remote process returned events /// /// The sender object /// The event args public delegate void RemoteProcessReturnedEventHandler(object sender, RemoteProcessReturnedEventArgs e); /// /// Remote process slot available event handler /// public abstract event RemoteProcessSlotAvailableEventHandler? RemoteProcessSlotAvailable; /// /// Remote process returned event handler /// public abstract event RemoteProcessReturnedEventHandler? RemoteProcessReturned; /// /// Will tell all remote machines that they can disconnect once their active processes are done /// Will also stop listening for new remote machines /// public abstract void DisableRemoteExecution(); /// /// Set max number of processes that can be executed remotely. /// Setting this can let the backend disconnect remote workers earlier /// public abstract void SetMaxRemoteProcessCount(uint count); /// /// Run a local process /// /// Process start info /// If the process should be run async /// Optional callback when the process exits /// Should be true unless process does not work being detoured (And in that case we need to manually register file system changes) /// The process being run public abstract IProcess RunProcess(ProcessStartInfo info, bool async, IProcess.ExitedEventHandler? exitedEventHandler, bool enableDetour); /// /// Run a remote process /// /// Process start info /// Optional callback when the process exits /// Number of cores this process uses /// Optionally contains input that we know process will need. Memory block containing zero-terminated strings with an extra termination in the end. /// Number of strings in known inputs /// True means that this process can run on a different architecture and expects a mapping to exist /// The remote process being run public abstract IProcess RunProcessRemote(ProcessStartInfo info, IProcess.ExitedEventHandler? exitedEventHandler, double weight = 1.0, byte[]? knownInputs = null, uint knownInputsCount = 0, bool canExecuteCrossArchitecture = false); /// /// Register roots data and get handle back /// /// Buffer containing roots used for cache and vfs. Format is multiples of byte/utf8string/utf8string. rootindex/vfspath/localpath /// Size of buffer in bytes /// The remote process being run public abstract ulong RegisterRoots(byte[] rootsData, uint rootsDataSize); /// /// Refresh cached information about directories /// /// The directories to refresh public abstract void RefreshDirectories(params string[] directories); /// /// Registers external files write to session caches /// /// The files to register public abstract void RegisterNewFiles(params string[] files); /// /// Registers virtual files that are part of other files (mapped into sections of existing file) /// /// Name of the virtual file /// Name of the source file /// Offset inside the source file /// Size of the segment inside the source file public abstract bool RegisterVirtualFile(string name, string sourceFile, ulong sourceOffset, ulong sourceSize); /// /// Registers the start of an external process /// /// The description of the process /// The process id that should be sent into EndExternalProcess public abstract uint BeginExternalProcess(string description); /// /// Registers the end of an external process /// /// The id returned by BeginExternalProcess /// The exit code of the external process public abstract void EndExternalProcess(uint id, uint exitCode); /// /// Writes external status to the uba trace stream which can then be visualized by ubavisualizer /// /// Total processes in session /// Processes done in session /// Number of errors in session public abstract void UpdateProgress(uint processesTotal, uint processesDone, uint errorCount); /// /// Writes external status to the uba trace stream which can then be visualized by ubavisualizer /// /// Row of status text. Reuse one index to show one line in visualizer /// The identation of status name that will be shown in visualizer /// The status text that will be shown in visualizer /// The status type /// Optional hyperlink that can be used to make text clickable in visualizer public abstract void UpdateStatus(uint statusRow, uint statusColumn, string statusText, LogEntryType statusType, string? statusLink = null); /// /// Set a custom cas key for a process's tracked inputs /// /// The file to track /// The working directory /// The process to get tracked inputs from public abstract void SetCustomCasKeyFromTrackedInputs(string file, string workingDirectory, IProcess process); /// /// Cancel all processes /// public abstract void CancelAll(); /// /// Print summary information to the logger /// public abstract void PrintSummary(); /// /// Create a ISessionServer object /// /// The session server create info /// The ISessionServer public static ISessionServer CreateSessionServer(ISessionServerCreateInfo info) { return new SessionServerImpl(info); } } }