1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 4 using System; 5 using System.Collections.Generic; 6 using System.IO; 7 using System.Runtime.Serialization.Formatters.Binary; 8 9 using Microsoft.Build.Framework; 10 using Microsoft.Build.BuildEngine.Shared; 11 12 namespace Microsoft.Build.BuildEngine 13 { 14 /// <summary> 15 /// This class is a container for node status 16 /// </summary> 17 internal class NodeStatus 18 { 19 #region Constructors 20 21 /// <summary> 22 /// Default constructor creating a NodeStatus 23 /// </summary> NodeStatus( int requestId, bool isActive, int queueDepth, long lastTaskActivityTimeStamp, long lastEngineActivityTimeStamp, bool isLaunchInProgress )24 internal NodeStatus 25 ( 26 int requestId, 27 bool isActive, 28 int queueDepth, 29 long lastTaskActivityTimeStamp, 30 long lastEngineActivityTimeStamp, 31 bool isLaunchInProgress 32 ) 33 { 34 this.requestId = requestId; 35 this.isActive = isActive; 36 this.queueDepth = queueDepth; 37 this.lastTaskActivityTimeStamp = lastTaskActivityTimeStamp; 38 this.lastEngineActivityTimeStamp = lastEngineActivityTimeStamp; 39 this.isLaunchInProgress = isLaunchInProgress; 40 this.unhandledException = null; 41 42 this.statusTimeStamp = DateTime.Now.Ticks; 43 } 44 45 /// <summary> 46 /// Create a node status describing an unhandled error 47 /// </summary> NodeStatus( Exception unhandledException )48 internal NodeStatus 49 ( 50 Exception unhandledException 51 ) 52 { 53 this.requestId = UnrequestedStatus; 54 this.isActive = true; 55 this.isLaunchInProgress = false; 56 this.unhandledException = unhandledException; 57 58 this.statusTimeStamp = DateTime.Now.Ticks; 59 } 60 61 /// <summary> 62 /// Create a node status indicating that breadth first traversal should be used 63 /// </summary> NodeStatus( bool useBreadthFirstTraversal )64 internal NodeStatus 65 ( 66 bool useBreadthFirstTraversal 67 ) 68 { 69 this.requestId = UnrequestedStatus; 70 this.isActive = true; 71 this.isLaunchInProgress = false; 72 this.unhandledException = null; 73 this.traversalType = useBreadthFirstTraversal; 74 } 75 76 /// <summary> 77 /// Create a node status indicating that node process has exited 78 /// </summary> NodeStatus( int requestId )79 internal NodeStatus 80 ( 81 int requestId 82 ) 83 { 84 this.requestId = requestId; 85 this.isActive = true; 86 this.isLaunchInProgress = false; 87 this.unhandledException = null; 88 this.hasExited = true; 89 } 90 #endregion 91 92 #region Properties 93 94 /// <summary> 95 /// The time period for which the node has been idle when the status report was filled out 96 /// </summary> 97 internal long TimeSinceLastTaskActivity 98 { 99 get 100 { 101 return (statusTimeStamp - lastTaskActivityTimeStamp); 102 } 103 } 104 105 106 /// <summary> 107 /// The time period for which the node has been idle when the status report was filled out 108 /// </summary> 109 internal long TimeSinceLastLoopActivity 110 { 111 get 112 { 113 return (statusTimeStamp - lastEngineActivityTimeStamp); 114 } 115 } 116 117 /// <summary> 118 /// The time stamp at which the node was last active 119 /// </summary> 120 internal long LastTaskActivity 121 { 122 get 123 { 124 return lastTaskActivityTimeStamp; 125 } 126 } 127 128 /// <summary> 129 /// The time stamp at which there was activity in the node's build loop 130 /// </summary> 131 internal long LastLoopActivity 132 { 133 get 134 { 135 return lastEngineActivityTimeStamp; 136 } 137 } 138 139 /// <summary> 140 /// True if the node is active (i.e. has been launched and can accept commands) 141 /// </summary> 142 internal bool IsActive 143 { 144 get 145 { 146 return this.isActive; 147 } 148 } 149 150 /// <summary> 151 /// True if the node process is no longer alive 152 /// </summary> 153 internal bool HasExited 154 { 155 get 156 { 157 return this.hasExited; 158 } 159 } 160 161 /// <summary> 162 /// The token of the request to which this is a response (-1 if status is unrequested) 163 /// </summary> 164 internal int RequestId 165 { 166 get 167 { 168 return this.requestId; 169 } 170 } 171 172 /// <summary> 173 /// The number of requests that need to be processed 174 /// </summary> 175 internal int QueueDepth 176 { 177 get 178 { 179 return this.queueDepth; 180 } 181 } 182 183 /// <summary> 184 /// The state of the targets which are in progress on the node 185 /// </summary> 186 internal TargetInProgessState [] StateOfInProgressTargets 187 { 188 get 189 { 190 return this.stateOfInProgressTargets; 191 } 192 set 193 { 194 this.stateOfInProgressTargets = value; 195 } 196 } 197 198 /// <summary> 199 /// True if the node is in the process of being launched, but is not yet active 200 /// </summary> 201 internal bool IsLaunchInProgress 202 { 203 get 204 { 205 return isLaunchInProgress; 206 } 207 } 208 209 /// <summary> 210 /// Returns the exception that occured on the node 211 /// </summary> 212 internal Exception UnhandledException 213 { 214 get 215 { 216 return unhandledException; 217 } 218 } 219 220 internal bool TraversalType 221 { 222 get 223 { 224 return traversalType; 225 } 226 } 227 #endregion 228 229 #region Data 230 private long statusTimeStamp; // the timestamp indicating when this status structure was filled out 231 private int requestId; // the token of the request to which this is a response (-1 if status is unrequested) 232 private bool isActive; // is the node active 233 private bool isLaunchInProgress; // is the node in the process of being launched 234 private int queueDepth; // the number of build request in the node's queue 235 private long lastTaskActivityTimeStamp; // the time stamp of the last task activity 236 private long lastEngineActivityTimeStamp; // the time stamp of the last engine activity 237 private TargetInProgessState[] stateOfInProgressTargets; 238 private Exception unhandledException; // unhandled exception 239 private bool traversalType; // if true use breadth first traversal 240 private bool hasExited; // if true the node process is no longer alive 241 private static BinaryFormatter formatter = new BinaryFormatter(); 242 internal const int UnrequestedStatus = -1; // used to indicate that the node is generating status without request 243 #endregion 244 245 #region CustomSerializationToStream WriteToStream(BinaryWriter writer)246 internal void WriteToStream(BinaryWriter writer) 247 { 248 writer.Write(traversalType); 249 writer.Write((Int64)statusTimeStamp); 250 writer.Write((Int32)requestId); 251 writer.Write(isActive); 252 writer.Write(isLaunchInProgress); 253 writer.Write((Int32)queueDepth); 254 writer.Write((Int64)lastTaskActivityTimeStamp); 255 writer.Write((Int64)lastEngineActivityTimeStamp); 256 257 if (stateOfInProgressTargets == null) 258 { 259 writer.Write((byte)0); 260 } 261 else 262 { 263 writer.Write((byte)1); 264 writer.Write((Int32)stateOfInProgressTargets.Length); 265 for (int i = 0; i < stateOfInProgressTargets.Length; i++) 266 { 267 if (stateOfInProgressTargets[i] == null) 268 { 269 writer.Write((byte)0); 270 } 271 else 272 { 273 writer.Write((byte)1); 274 stateOfInProgressTargets[i].WriteToStream(writer); 275 } 276 } 277 } 278 279 if (unhandledException == null) 280 { 281 writer.Write((byte)0); 282 } 283 else 284 { 285 writer.Write((byte)1); 286 formatter.Serialize(writer.BaseStream, unhandledException); 287 } 288 } 289 CreateFromStream(BinaryReader reader)290 internal static NodeStatus CreateFromStream(BinaryReader reader) 291 { 292 NodeStatus status = new NodeStatus(null); 293 status.traversalType = reader.ReadBoolean(); 294 status.statusTimeStamp = reader.ReadInt64(); 295 status.requestId = reader.ReadInt32(); 296 status.isActive = reader.ReadBoolean(); 297 status.isLaunchInProgress = reader.ReadBoolean(); 298 status.queueDepth = reader.ReadInt32(); 299 status.lastTaskActivityTimeStamp = reader.ReadInt64(); 300 status.lastEngineActivityTimeStamp = reader.ReadInt64(); 301 302 if (reader.ReadByte() == 0) 303 { 304 status.stateOfInProgressTargets = null; 305 } 306 else 307 { 308 int numberOfInProgressTargets = reader.ReadInt32(); 309 status.stateOfInProgressTargets = new TargetInProgessState[numberOfInProgressTargets]; 310 for (int i = 0; i < numberOfInProgressTargets; i++) 311 { 312 if (reader.ReadByte() == 0) 313 { 314 status.stateOfInProgressTargets[i] = null; 315 } 316 else 317 { 318 TargetInProgessState state = new TargetInProgessState(); 319 state.CreateFromStream(reader); 320 status.stateOfInProgressTargets[i] = state; 321 } 322 } 323 } 324 325 if (reader.ReadByte() == 0) 326 { 327 status.unhandledException = null; 328 } 329 else 330 { 331 status.unhandledException = (Exception)formatter.Deserialize(reader.BaseStream); 332 } 333 return status; 334 } 335 #endregion 336 } 337 } 338