/// <summary> /// Populates the module specific mount expanders from modules in the module configurations /// </summary> /// <param name="modules">the module configurations</param> /// <param name="moduleMountTables">the module mounts tables</param> /// <returns>true if the operations were performed successfully</returns> public bool PopulateModuleMounts(IEnumerable <IModuleConfiguration> modules, out IDictionary <ModuleId, MountsTable> moduleMountTables) { moduleMountTables = new Dictionary <ModuleId, MountsTable>(); bool success = true; foreach (var module in modules) { if (module.Mounts.Count != 0) { MountsTable moduleMountsTable = new MountsTable(this, module.ModuleId); foreach (var mount in module.Mounts) { moduleMountsTable.AddResolvedMount(mount); } moduleMountTables[module.ModuleId] = moduleMountsTable; success &= moduleMountsTable.CompleteInitialization(); } } if (!success) { moduleMountTables = null; } return(success); }
private IPipGraphBuilder CreatePipGraphBuilder( LoggingContext loggingContext, MountsTable mountsTable, [CanBeNull] GraphReuseResult reuseResult) { var builder = new PipGraph.Builder( EngineSchedule.CreateEmptyPipTable(Context), Context, Scheduler.Tracing.Logger.Log, loggingContext, Configuration, mountsTable.MountPathExpander, fingerprintSalt: Configuration.Cache.CacheSalt, directoryMembershipFingerprinterRules: new Scheduler.DirectoryMembershipFingerprinterRuleSet(Configuration, Context.StringTable)); PatchablePipGraph patchableGraph = null; if (Configuration.FrontEnd.UseGraphPatching() && reuseResult?.IsPartialReuse == true) { Logger.Log.UsingPatchableGraphBuilder(loggingContext); patchableGraph = new PatchablePipGraph( oldPipGraph: reuseResult.PipGraph.DataflowGraph, oldPipTable: reuseResult.PipGraph.PipTable, graphBuilder: builder, maxDegreeOfParallelism: Configuration.FrontEnd.MaxFrontEndConcurrency()); } return((IPipGraphBuilder)patchableGraph ?? builder); }
private void AddConfigurationMounts(MountsTable mountsTable) { // Add configuration mounts foreach (var mount in Configuration.Mounts) { mountsTable.AddResolvedMount(mount, new LocationData(Configuration.Layout.PrimaryConfigFile, 0, 0)); } }
private bool CompleteInitialization(LoggingContext loggingContext, MountsTable mountsTable) { if (!mountsTable.CompleteInitialization()) { Contract.Assume(loggingContext.ErrorWasLogged, "An error should have been logged after MountTable.CompleteInitialization()"); return(false); } return(true); }
/// <summary> /// Private constructor. Please use CreateAndRegister factory method. /// </summary> private MountsTable(LoggingContext loggingContext, BuildXLContext context, MountPathExpander mountPathExpander = null) { m_parent = null; m_loggingContext = loggingContext; m_context = context; MountPathExpander = mountPathExpander ?? new MountPathExpander(context.PathTable); m_mountMapBuilder = new ConcurrentDictionary <AbsolutePath, IMount>(); m_mountsByName = new ConcurrentDictionary <string, IMount>(StringComparer.OrdinalIgnoreCase); m_mountPathIdentifiersByMount = new ConcurrentDictionary <IMount, PathAtom>(); m_mountLocationsByMount = new ConcurrentDictionary <IMount, LocationData>(); m_alternativeRoots = new ConcurrentDictionary <AbsolutePath, IMount>(); }
/// <summary> /// Creates a default mount table with the regular system and configuration defined mounts and sets it. /// </summary> public bool TryPopulateWithDefaultMountsTable(LoggingContext loggingContext, BuildXLContext buildXLContext, IConfiguration configuration, IReadOnlyDictionary <string, string> properties) { var mountsTable = MountsTable.CreateAndRegister(loggingContext, buildXLContext, configuration, properties); if (!mountsTable.CompleteInitialization()) { return(false); } SetMountsTable(mountsTable); return(true); }
private static void RegisterRedirectedMount( BuildXLContext context, IReadOnlyDictionary <string, string> properties, MountsTable table, string mountName, string envVariable = null, bool allowCreateDirectory = false) { envVariable = envVariable ?? mountName.ToCanonicalizedEnvVar(); if (!properties.TryGetValue(envVariable, out string redirectedPath)) { Contract.Assert(false, $"Failed to register a redirected mount ('{mountName}') using a path defined by '{envVariable}' environment variable. The variable was not specified."); } table.AddStaticSystemMount(mountName, redirectedPath, allowCreateDirectory); // We don't need to add the real path of redirected mount into alternative roots. // Internally inside BuildXL itself, all accesses to user-related paths should go through the redirected paths by querying the mount table, // e.g. in DScript, one should use Context.getMount(...) to get user-related paths. // For any executed tool, if the tool accesses a user-related path, then the directory translation will translate that path into the redirected one. // We also don't want to add the real paths to the mount table because those paths will also go to the path expander that is part of the cached graph. // If the graph is used across builds, then the real user-related paths are not guaranteed to be the same. }
public static MountsTable CreateAndRegister( LoggingContext loggingContext, BuildXLContext context, IConfiguration configuration, [CanBeNull] IReadOnlyDictionary <string, string> properties) { Contract.Requires(context != null); Contract.Requires(configuration != null); Contract.Requires(loggingContext != null); ILayoutConfiguration layout = configuration.Layout; IReadOnlyList <IResolverSettings> resolverSettings = configuration.Resolvers; var table = new MountsTable(loggingContext, context); // If any resolver settings allows for a writable source directory, then the source directory is writable var writableSourceRoot = resolverSettings.Any(resolverSetting => resolverSetting.AllowWritableSourceDirectory); table.AddStaticMount("BuildEnginePath", layout.BuildEngineDirectory, isWriteable: false); table.AddStaticMount("SourceRoot", layout.SourceDirectory, isWriteable: writableSourceRoot); table.AddStaticMount("ObjectRoot", layout.ObjectDirectory, isWriteable: true, isScrubbable: true); table.AddStaticMount( "LogsDirectory", configuration.Logging.RedirectedLogsDirectory.IsValid ? configuration.Logging.RedirectedLogsDirectory : configuration.Logging.LogsDirectory, isWriteable: true, allowCreateDirectory: true); if (layout.FrontEndDirectory.IsValid) { // This location is used only for storing nuget packages and generated specs so far. table.AddStaticMount("FrontEnd", layout.FrontEndDirectory, isWriteable: true, isScrubbable: false); } if (layout.TempDirectory.IsValid) { table.AddStaticMount("TempRoot", layout.TempDirectory, isWriteable: true, isScrubbable: true); } // Cross Plat supported MountPoints table.AddStaticSystemMount("ProgramData", Environment.SpecialFolder.CommonApplicationData); table.AddStaticSystemMount("ProgramFiles", Environment.SpecialFolder.ProgramFiles, trackSourceFileChanges: true); table.AddStaticSystemMount("System", Environment.SpecialFolder.System); if (!layout.RedirectedUserProfileJunctionRoot.IsValid) { table.AddStaticSystemMount("UserProfile", Environment.SpecialFolder.UserProfile); table.AddStaticSystemMount("AppData", Environment.SpecialFolder.ApplicationData, allowCreateDirectory: true); table.AddStaticSystemMount("LocalAppData", Environment.SpecialFolder.LocalApplicationData, allowCreateDirectory: true); } else { // User profile is redirected; need to use the paths specified in the env block. Contract.Assert(properties != null); RegisterRedirectedMount(context, properties, table, "UserProfile"); RegisterRedirectedMount(context, properties, table, "AppData", allowCreateDirectory: true); RegisterRedirectedMount(context, properties, table, "LocalAppData", allowCreateDirectory: true); } if (!OperatingSystemHelper.IsUnixOS) { // Add system mounts that are Windows Only table.AddStaticSystemMount("Windows", Environment.SpecialFolder.Windows); table.AddStaticSystemMount("ProgramFilesX86", Environment.SpecialFolder.ProgramFilesX86, trackSourceFileChanges: true); table.AddStaticSystemMount("CommonProgramFiles", Environment.SpecialFolder.CommonProgramFiles, trackSourceFileChanges: true); table.AddStaticSystemMount("CommonProgramFilesX86", Environment.SpecialFolder.CommonProgramFilesX86, trackSourceFileChanges: true); if (!layout.RedirectedUserProfileJunctionRoot.IsValid) { table.AddStaticSystemMount("InternetCache", Environment.SpecialFolder.InternetCache); table.AddStaticSystemMount("InternetHistory", Environment.SpecialFolder.History); table.AddStaticSystemMount("INetCookies", Environment.SpecialFolder.Cookies, allowCreateDirectory: true); table.AddStaticSystemMount("LocalLow", FileUtilities.KnownFolderLocalLow); } else { // User profile is redirected; need to use the paths specified in the env block. Contract.Assert(properties != null); RegisterRedirectedMount(context, properties, table, "InternetCache"); RegisterRedirectedMount(context, properties, table, "InternetHistory"); RegisterRedirectedMount(context, properties, table, "INetCookies", allowCreateDirectory: true); RegisterRedirectedMount(context, properties, table, "LocalLow"); } } else { table.AddStaticSystemMount("Applications", MacPaths.Applications, trackSourceFileChanges: true); table.AddStaticSystemMount("Bin", MacPaths.Bin, trackSourceFileChanges: true); table.AddStaticSystemMount("UsrBin", MacPaths.UsrBin, trackSourceFileChanges: true); table.AddStaticSystemMount("UsrInclude", MacPaths.UsrInclude, trackSourceFileChanges: true); table.AddStaticSystemMount("UsrLib", MacPaths.UsrLib, trackSourceFileChanges: true); table.AddStaticSystemMount("Library", MacPaths.Library, trackSourceFileChanges: true); table.AddStaticSystemMount("UserProvisioning", MacPaths.UserProvisioning, trackSourceFileChanges: true); } return(table); }
/// <summary> /// Private constructor used for creating module specific mount tables /// </summary> private MountsTable(MountsTable parent, ModuleId moduleId) : this(parent.m_loggingContext, parent.m_context) { m_parent = parent; MountPathExpander = parent.MountPathExpander.CreateModuleMountExpander(moduleId); }
/// <nodoc /> public void SetMountsTable(MountsTable mountsTable) { m_mountsTable = mountsTable; }
private bool AddConfigurationMountsAndCompleteInitialization(LoggingContext loggingContext, MountsTable mountsTable) { // Add configuration mounts foreach (var mount in Configuration.Mounts) { mountsTable.AddResolvedMount(mount, new LocationData(Configuration.Layout.PrimaryConfigFile, 0, 0)); } if (!mountsTable.CompleteInitialization()) { Contract.Assume(loggingContext.ErrorWasLogged, "An error should have been logged after MountTable.CompleteInitialization()"); return(false); } return(true); }
private bool ConstructAndEvaluateGraph( LoggingContext loggingContext, FrontEndEngineAbstraction frontEndEngineAbstration, CacheInitializationTask engineCacheTask, MountsTable mountsTable, EvaluationFilter evaluationFilter, [CanBeNull] GraphReuseResult reuseResult, out PipGraph pipGraph) { Contract.Requires(frontEndEngineAbstration != null); Contract.Requires(engineCacheTask != null); Contract.Requires(mountsTable != null); pipGraph = null; IPipGraphBuilder pipGraphBuilder = null; if (!AddConfigurationMountsAndCompleteInitialization(loggingContext, mountsTable)) { return(false); } IDictionary <ModuleId, MountsTable> moduleMountsTableMap; if (!mountsTable.PopulateModuleMounts(Configuration.ModulePolicies.Values, out moduleMountsTableMap)) { Contract.Assume(loggingContext.ErrorWasLogged, "An error should have been logged after MountTable.PopulateModuleMounts()"); return(false); } m_visualization?.MountsTable.MakeAvailable(mountsTable); if ((Configuration.Engine.Phase & EnginePhases.Schedule) != 0) { pipGraphBuilder = CreatePipGraphBuilder(loggingContext, mountsTable, reuseResult); } // Have to do some horrible magic here to get to a proper Task<T> with the BuildXL cache since // someone updated the engine cache to be an await style pattern, and there is no way to get to the EngineCache // If the cache was fast to startup, but perhaps blocked itself on first access we wouldn't have to do all these hoops. Func <Task <Possible <EngineCache> > > getBuildCacheTask = async() => { return((await engineCacheTask).Then(engineCache => engineCache.CreateCacheForContext())); }; if (!FrontEndController.PopulateGraph( getBuildCacheTask(), pipGraphBuilder, frontEndEngineAbstration, evaluationFilter, Configuration, m_initialCommandLineConfiguration.Startup)) { LogFrontEndStats(loggingContext); Contract.Assume(loggingContext.ErrorWasLogged, "An error should have been logged after FrontEndController.PopulateGraph()"); return(false); } LogFrontEndStats(loggingContext); // Pip graph must become immutable now that evaluation is done (required to construct a scheduler). return(pipGraphBuilder == null || (pipGraph = pipGraphBuilder.Build()) != null); }
/// <summary> /// Check if pip graph can be reused. /// /// There are 3 opportunities to determine a graph match. The applicability of each depends on the distributed build roles. /// (1) from engine cache, /// (2) from content cache, and /// (3) from master node (if running on a worker node in a distributed build) /// </summary> private GraphCacheCheckStatistics CheckGraphCacheReuse( LoggingContext outerLoggingContext, int maxDegreeOfParallelism, GraphFingerprint graphFingerprint, IReadOnlyDictionary <string, string> properties, CacheInitializationTask cacheInitializationTask, JournalState journalState, out EngineSerializer serializer, out InputTracker.InputChanges inputChanges) { serializer = CreateEngineSerializer(outerLoggingContext); inputChanges = null; var cacheGraphStats = default(GraphCacheCheckStatistics); using (var timeBlock = TimedBlock <EmptyStruct, GraphCacheCheckStatistics> .Start( outerLoggingContext, Statistics.GraphCacheReuseCheck, (context, emptyStruct) => Logger.Log.CheckingForPipGraphReuseStart(context), default(EmptyStruct), (loggingContext, stats) => { Logger.Log.CheckingForPipGraphReuseComplete(loggingContext, stats); // On misses we want to give the user a message for why there was a miss if (!stats.WasHit) { Contract.Assume(stats.MissReason != GraphCacheMissReason.NoMiss); Logger.Log.GraphNotReusedDueToChangedInput(loggingContext, stats.MissMessageForConsole, stats.MissDescription); } m_enginePerformanceInfo.GraphCacheCheckDurationMs = stats.ElapsedMilliseconds; m_enginePerformanceInfo.GraphCacheCheckJournalEnabled = stats.JournalEnabled; }, () => cacheGraphStats)) { var loggingContext = timeBlock.LoggingContext; var effectiveEnvironmentVariables = FrontEndEngineImplementation.PopulateFromEnvironmentAndApplyOverrides(properties); var availableMounts = MountsTable.CreateAndRegister(loggingContext, Context, Configuration, m_initialCommandLineConfiguration.Startup.Properties); if (!AddConfigurationMountsAndCompleteInitialization(loggingContext, availableMounts)) { return(cacheGraphStats); } cacheGraphStats.JournalEnabled = journalState.IsEnabled; // ************************************************************ // 1. Engine cache check: // ************************************************************ // * Single machine builds // Distributed builds rely on the graph being available via the cache for it to be shared between master // and workers. So even if the master could have had a hit from the engine cache, it must be ignored // since the workers would not be able to retrieve it. if (!HasExplicitlyLoadedGraph(Configuration.Cache) && !Configuration.Schedule.ForceUseEngineInfoFromCache && Configuration.Distribution.BuildRole == DistributedBuildRoles.None) { Contract.Assume( graphFingerprint != null, "When looking up a cached graph on a distributed master or single-machine build, a graph fingerprint must be computed"); InputTracker.MatchResult engineCacheMatchResult = CheckIfAvailableInputsToGraphMatchPreviousRun( loggingContext, serializer, graphFingerprint: graphFingerprint, availableEnvironmentVariables: effectiveEnvironmentVariables, availableMounts: availableMounts, journalState: journalState, maxDegreeOfParallelism: maxDegreeOfParallelism); cacheGraphStats.ObjectDirectoryHit = engineCacheMatchResult.Matches; cacheGraphStats.ObjectDirectoryMissReason = engineCacheMatchResult.MissType; cacheGraphStats.MissReason = engineCacheMatchResult.MissType; cacheGraphStats.MissDescription = engineCacheMatchResult.FirstMissIdentifier; cacheGraphStats.WasHit = engineCacheMatchResult.Matches; cacheGraphStats.InputFilesChecked = engineCacheMatchResult.FilesChecked; // Checking the engine cache may have used a FileChangeTracker and provided information about // files/ContentHash pairs that were unchanged from the previous run. Hold onto this information as it may // be useful when eventually parsing files. // The FileChangeTracker is now up to date. All changed files have been removed from it. It can be reused // for a future build with the same fingerprint, though it may be tracking extra files, for example if // a spec was removed since the previous build. inputChanges = engineCacheMatchResult.InputChanges; } var shouldTryContentCache = !cacheGraphStats.WasHit && Configuration.Distribution.BuildRole != DistributedBuildRoles.Worker && Configuration.Cache.AllowFetchingCachedGraphFromContentCache && !HasExplicitlyLoadedGraph(Configuration.Cache) && (!Configuration.FrontEnd.UseSpecPublicFacadeAndAstWhenAvailable.HasValue || !Configuration.FrontEnd.UseSpecPublicFacadeAndAstWhenAvailable.Value); // ************************************************************ // 2. Content cache check: // ************************************************************ // * Single machine builds that missed earlier // * Distributed masters // This is the only valid place for the master to get a hit since it must be in the cache for the // workers to get it. if (shouldTryContentCache) { // Since an in-place match did not succeed, we need a readied cache to try again. // TODO: This logs an error if it fails. We are assuming some later thing will ensure that, if failed, // the engine fails overall. Possible <CacheInitializer> possibleCacheInitializerForFallback = cacheInitializationTask.GetAwaiter().GetResult(); if (possibleCacheInitializerForFallback.Succeeded) { CacheInitializer cacheInitializerForFallback = possibleCacheInitializerForFallback.Result; using (EngineCache cacheForFallback = cacheInitializerForFallback.CreateCacheForContext()) { var cacheGraphProvider = new CachedGraphProvider( loggingContext, Context, cacheForFallback, FileContentTable, maxDegreeOfParallelism); var cachedGraphDescriptor = cacheGraphProvider.TryGetPipGraphCacheDescriptorAsync(graphFingerprint, effectiveEnvironmentVariables, availableMounts.MountsByName).Result; if (cachedGraphDescriptor == null) { // There was no matching fingerprint in the cache. Record the status for logging before returning. cacheGraphStats.CacheMissReason = GraphCacheMissReason.FingerprintChanged; SetMissReasonIfUnset(ref cacheGraphStats, cacheGraphStats.CacheMissReason); return(cacheGraphStats); } var fetchEngineScheduleContent = EngineSchedule.TryFetchFromCacheAsync( loggingContext, Context, cacheForFallback, cachedGraphDescriptor, serializer, FileContentTable, m_tempCleaner).Result; if (!fetchEngineScheduleContent) { cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoPreviousRunToCheck; SetMissReasonIfUnset(ref cacheGraphStats, cacheGraphStats.CacheMissReason); return(cacheGraphStats); } // If a distributed master, take note of the graph fingerprint if (Configuration.Distribution.BuildRole == DistributedBuildRoles.Master) { Contract.Assert(cachedGraphDescriptor != null); m_masterService.CachedGraphDescriptor = cachedGraphDescriptor; } Logger.Log.FetchedSerializedGraphFromCache(outerLoggingContext); cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoMiss; cacheGraphStats.MissReason = cacheGraphStats.CacheMissReason; cacheGraphStats.WasHit = true; } } else { cacheGraphStats.CacheMissReason = GraphCacheMissReason.CacheFailure; SetMissReasonIfUnset(ref cacheGraphStats, cacheGraphStats.CacheMissReason); return(cacheGraphStats); } } // ************************************************************ // 3. Query distributed master // ************************************************************ // * Distributed workers only if (Configuration.Distribution.BuildRole == DistributedBuildRoles.Worker) { Contract.Assume( graphFingerprint == null, "Distributed workers should request a graph fingerprint from the master (not compute one locally)"); Possible <CacheInitializer> possibleCacheInitializerForWorker = cacheInitializationTask.GetAwaiter().GetResult(); Contract.Assume(possibleCacheInitializerForWorker.Succeeded, "Workers must have a valid cache"); CacheInitializer cacheInitializerForWorker = possibleCacheInitializerForWorker.Result; using (EngineCache cacheForWorker = cacheInitializerForWorker.CreateCacheForContext()) { PipGraphCacheDescriptor schedulerStateDescriptor; if (!m_workerService.TryGetBuildScheduleDescriptor(out schedulerStateDescriptor) || !EngineSchedule.TryFetchFromCacheAsync( outerLoggingContext, Context, cacheForWorker, schedulerStateDescriptor, serializer, FileContentTable, m_tempCleaner).Result) { cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoFingerprintFromMaster; cacheGraphStats.MissReason = cacheGraphStats.CacheMissReason; return(cacheGraphStats); } AsyncOut <AbsolutePath> symlinkFileLocation = new AsyncOut <AbsolutePath>(); if (!SymlinkDefinitionFileProvider.TryFetchWorkerSymlinkFileAsync( outerLoggingContext, Context.PathTable, cacheForWorker, Configuration.Layout, m_workerService, symlinkFileLocation).Result) { cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoFingerprintFromMaster; cacheGraphStats.MissReason = cacheGraphStats.CacheMissReason; return(cacheGraphStats); } m_workerSymlinkDefinitionFile = symlinkFileLocation.Value; // Success. Populate the stats cacheGraphStats.WasHit = true; cacheGraphStats.WorkerHit = true; cacheGraphStats.MissReason = GraphCacheMissReason.NoMiss; cacheGraphStats.CacheMissReason = GraphCacheMissReason.NoMiss; } } } return(cacheGraphStats); }
/// <summary> /// Creates an instance of <see cref="FrontEndEngineImplementation"/>. /// </summary> public FrontEndEngineImplementation( LoggingContext loggingContext, PathTable pathTable, IConfiguration configuration, IStartupConfiguration startupConfiguration, MountsTable mountsTable, InputTracker inputTracker, SnapshotCollector snapshotCollector, DirectoryTranslator directoryTranslator, Func <FileContentTable> getFileContentTable, int timerUpdatePeriod, bool isPartialReuse, IEnumerable <IFrontEnd> registeredFrontends) { Contract.Requires(loggingContext != null); Contract.Requires(pathTable != null); Contract.Requires(configuration != null); Contract.Requires(startupConfiguration != null); Contract.Requires(mountsTable != null); Contract.Requires(inputTracker != null); Contract.Requires(getFileContentTable != null); Contract.Requires(registeredFrontends != null); m_loggingContext = loggingContext; PathTable = pathTable; m_mountsTable = mountsTable; m_inputTracker = inputTracker; m_getFileContentTable = getFileContentTable; m_isPartialReuse = isPartialReuse; m_frontendsEnvironmentRestriction = registeredFrontends.ToDictionary(frontend => frontend.Name, frontEnd => frontEnd.ShouldRestrictBuildParameters); m_snapshotCollector = snapshotCollector; GetTimerUpdatePeriod = timerUpdatePeriod; Layout = configuration.Layout; if (ShouldUseSpecCache(configuration)) { m_specCache = new FileCombiner( loggingContext, Path.Combine(configuration.Layout.EngineCacheDirectory.ToString(PathTable), SpecCacheFileName), FileCombiner.FileCombinerUsage.SpecFileCache, configuration.FrontEnd.LogStatistics); } m_allBuildParameters = new ConcurrentDictionary <string, TrackedValue>(StringComparer.OrdinalIgnoreCase); foreach (var kvp in PopulateFromEnvironmentAndApplyOverrides(loggingContext, startupConfiguration.Properties).ToDictionary()) { m_allBuildParameters.TryAdd(kvp.Key, new TrackedValue(kvp.Value, false)); } m_localDiskContentStore = new LocalDiskContentStore( loggingContext, PathTable, m_getFileContentTable(), m_inputTracker.FileChangeTracker, directoryTranslator, vfsCasRoot: configuration.Cache.VfsCasRoot); m_localDiskContentStoreConcurrencyLimiter = new ActionBlockSlim <MaterializeFileRequest>( Environment.ProcessorCount, request => { var requestCompletionSource = request.CompletionSource; try { var materializeResult = m_localDiskContentStore.TryMaterializeAsync( request.Cache, request.FileRealizationModes, request.Path, request.ContentHash, trackPath: request.TrackPath, recordPathInFileContentTable: request.RecordPathInFileContentTable).GetAwaiter().GetResult(); requestCompletionSource.SetResult(materializeResult); } catch (TaskCanceledException) { requestCompletionSource.SetCanceled(); } catch (Exception e) { requestCompletionSource.SetException(e); } }); }
/// <nodoc /> public void SetMountsTable(MountsTable mountsTable) { m_customMountsTable = mountsTable.AllMountsSoFar.ToDictionary(mount => mount.Name.ToString(m_pathTable.StringTable), mount => mount); }