File: BackEnd\Components\Communications\TaskHostNodeManager.cs
Web Access
Project: ..\..\..\src\Build\Microsoft.Build.csproj (Microsoft.Build)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Build.Execution;
using Microsoft.Build.Shared;
 
#nullable disable
 
namespace Microsoft.Build.BackEnd
{
    /// <summary>
    /// The NodeManager class is responsible for marshalling data to/from the NodeProviders and organizing the
    /// creation of new nodes on request.
    /// </summary>
    internal class TaskHostNodeManager : INodeManager
    {
        /// <summary>
        /// The node provider for task hosts.
        /// </summary>
        private INodeProvider _outOfProcTaskHostNodeProvider;
 
        /// <summary>
        /// The build component host.
        /// </summary>
        private IBuildComponentHost _componentHost;
 
        /// <summary>
        /// Tracks whether ShutdownComponent has been called.
        /// </summary>
        private bool _componentShutdown;
 
        /// <summary>
        /// Constructor.
        /// </summary>
        private TaskHostNodeManager()
        {
            // do nothing
        }
 
        #region INodeManager Members
 
        /// <summary>
        /// Creates a node on an available NodeProvider, if any..
        /// Not used - base class <see cref="NodeProviderOutOfProcBase"/> implementation is reused instead.
        /// </summary>
        public IList<NodeInfo> CreateNodes(NodeConfiguration configuration, NodeAffinity affinity, int numberOfNodesToCreate)
            => throw new NotSupportedException("not used");
 
        /// <summary>
        /// Sends data to the specified node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="packet">The packet to send.</param>
        public void SendData(int node, INodePacket packet)
        {
            throw new NotSupportedException("not used");
        }
 
        /// <summary>
        /// Shuts down all of the connected managed nodes.
        /// </summary>
        /// <param name="enableReuse">Flag indicating if nodes should prepare for reuse.</param>
        public void ShutdownConnectedNodes(bool enableReuse)
        {
            ErrorUtilities.VerifyThrow(!_componentShutdown, "We should never be calling ShutdownNodes after ShutdownComponent has been called");
            _outOfProcTaskHostNodeProvider?.ShutdownConnectedNodes(enableReuse);
        }
 
        /// <summary>
        /// Shuts down all of the managed nodes permanently.
        /// </summary>
        public void ShutdownAllNodes()
        {
            _outOfProcTaskHostNodeProvider?.ShutdownAllNodes();
        }
        #endregion
 
        #region IBuildComponent Members
 
        /// <summary>
        /// Initializes the component
        /// </summary>
        /// <param name="host">The component host</param>
        public void InitializeComponent(IBuildComponentHost host)
        {
            ErrorUtilities.VerifyThrow(_componentHost == null, "TaskHostNodeManager already initialized.");
            ErrorUtilities.VerifyThrow(host != null, "We can't create a TaskHostNodeManager with a null componentHost");
 
            _componentHost = host;
            _outOfProcTaskHostNodeProvider = _componentHost.GetComponent(BuildComponentType.OutOfProcTaskHostNodeProvider) as INodeProvider;
            _componentShutdown = false;
        }
 
        /// <summary>
        /// Shuts down the component.
        /// </summary>
        public void ShutdownComponent()
        {
            _outOfProcTaskHostNodeProvider = null;
            _componentHost = null;
            _componentShutdown = true;
 
            ClearPerBuildState();
        }
 
        /// <summary>
        /// Reset the state of objects in the node manager which need to be reset between builds.
        /// </summary>
        public void ClearPerBuildState()
        {
            // do nothing
        }
 
        #endregion
 
        #region INodePacketFactory Members
 
        /// <summary>
        /// Registers the specified handler for a particular packet type.
        /// </summary>
        /// <param name="packetType">The packet type.</param>
        /// <param name="factory">The factory for packets of the specified type.</param>
        /// <param name="handler">The handler to be called when packets of the specified type are received.</param>
        public void RegisterPacketHandler(NodePacketType packetType, NodePacketFactoryMethod factory, INodePacketHandler handler)
        {
            throw new NotSupportedException("not used");
        }
 
        /// <summary>
        /// Unregisters a packet handler.
        /// </summary>
        /// <param name="packetType">The packet type.</param>
        public void UnregisterPacketHandler(NodePacketType packetType)
        {
            throw new NotSupportedException("not used");
        }
 
        /// <summary>
        /// Takes a serializer, deserializes the packet and routes it to the appropriate handler.
        /// </summary>
        /// <param name="nodeId">The node from which the packet was received.</param>
        /// <param name="packetType">The packet type.</param>
        /// <param name="translator">The translator containing the data from which the packet should be reconstructed.</param>
        public void DeserializeAndRoutePacket(int nodeId, NodePacketType packetType, ITranslator translator)
        {
            throw new NotSupportedException("not used");
        }
 
        /// <summary>
        /// Routes the specified packet. This is called by the Inproc node directly since it does not have to do any deserialization
        /// </summary>
        /// <param name="nodeId">The node from which the packet was received.</param>
        /// <param name="packet">The packet to route.</param>
        public void RoutePacket(int nodeId, INodePacket packet)
        {
            throw new NotSupportedException("not used");
        }
 
        #endregion
 
        /// <summary>
        /// Factory for component creation.
        /// </summary>
        internal static IBuildComponent CreateComponent(BuildComponentType type)
        {
            ErrorUtilities.VerifyThrow(type == BuildComponentType.TaskHostNodeManager, "Cannot create component of type {0}", type);
            return new TaskHostNodeManager();
        }
 
        IEnumerable<Process> INodeManager.GetProcesses()
        {
            return _outOfProcTaskHostNodeProvider.GetProcesses();
        }
    }
}