/// <summary> /// The dispatch action called when a status request is signaled. /// </summary> /// <param name="state">The server state object of the network connection.</param> public static void status(ServerState state) { ServerStatus status = new ServerStatus(); status.NodeCount = Nodes.GetTotalAvailableNodeCount(); status.CPUCount = Nodes.GetCPUCount(); status.CDPI = Nodes.GetCDPI(); status.TotalMemory = Nodes.GetTotalMemory(); SerializationEngine serializer = new SerializationEngine(); state.WriteAndClose(MessageType.STATUS_TERMINAL, serializer.Serialize(status)); }
/// <summary> /// Execute an incoming job. /// </summary> /// <param name="methodName">The name of the procedure to be executed.</param> /// <param name="typeName">The name of the type held within the assembly for with the procedure to be executed resides.</param> /// <param name="assemblyName">The name of the assembly the procedure resides in.</param> /// <param name="parameter">The parameter passed to the executed procedure.</param> /// <returns>The result of the execution serialized for transport.</returns> public byte[] ExecuteIncoming(string methodName, string typeName, string assemblyName, byte[] parameter) { SerializationEngine serializer = new SerializationEngine (); PrestoParameter param = (PrestoParameter)serializer.Deserialize(parameter); Assembly assembly = assemblies[assemblyName]; Type type = assembly.GetType(typeName, false, true); MethodInfo method = type.GetMethod(methodName); PrestoResult res = (PrestoResult)method.Invoke(null, new object[] { param }); return serializer.Serialize(res); }
/// <summary> /// Internal execute function to be called asynchronously. /// </summary> /// <param id="state">The server state object associated with the execution.</param> private static void execute(ServerState state) { Interlocked.Increment(ref runningJobs); //get the execution context SerializationEngine serializer = new SerializationEngine (); Transfers.ExecutionContext context = (Transfers.ExecutionContext)serializer.Deserialize(state.GetDataArray()); byte[] res = DomainManager.ExecuteIncoming(context); Transfers.ExecutionResult result = new Transfers.ExecutionResult(res, context.ContextID, context.DomainKey, ClusterManager.NodeID); state.Write(MessageType.EXECUTION_COMPLETE, serializer.Serialize(result)); Interlocked.Decrement(ref runningJobs); }
/// <summary> /// A dispatch event to be rasied upon reception of an assembly from another Presto server.. /// </summary> /// <param id="state">The server state object recieved along with this event.</param> private static void recieveAssemblySlave(ServerState state) { //get the slave assembly struct SerializationEngine serializer = new SerializationEngine (); SlaveAssembly slaveAssembly = (SlaveAssembly)serializer.Deserialize(state.GetDataArray()); //create the domain and add the assembly to it DomainManager.CreateDomain(slaveAssembly.DomainKey); if(!DomainManager.DomainHasAssembly(slaveAssembly.DomainKey, slaveAssembly.AssemblyName)){ DomainManager.LoadAssemblyIntoDomain(slaveAssembly.DomainKey, slaveAssembly.AssemblyImage); } Presto.Remote.Node from = Nodes.GetNodeByID(slaveAssembly.NodeID); if (from != null) { from.SetLoadedAssembly(slaveAssembly.AssemblyName); from.SetLoadedDomain(slaveAssembly.DomainKey); } //send back assembly transfer complete message state.Write(MessageType.ASSEMBLY_TRANSFER_COMPLETE); }
//------------Methods-----------------------// /// <summary> /// Deploys an execution job into the cluster. /// /// The method passed in as "function" MUST be static. If it is not, an error will be thrown and added to the error log. /// Instance data is not preserved outside of the running ApplicationDomain and indeed all data not instantiated within the /// method or not globally synchronized using a cluster data structure is considered volatile, mutable, inconsitent and untrustworthy. /// /// DO NOT write code that will depend on instance or static class variables in order to do processing /// unless those variables are declared constant from the start of the module. Write functions as if they are black boxes, /// the only thing you see is input and output. /// </summary> /// <param name="function">The function to be executed.</param> /// <param name="parameter">The parameter to be passed into the executed function.</param> /// <param name="callback">The callback to be executed when the function completes.</param> /// <returns>The execution ID of this particular execution.</returns> public static string Execute(Func<PrestoParameter, PrestoResult> function, PrestoParameter parameter, Action<PrestoResult> callback) { //set the event to non signaled jobCompletionEvent.Reset(); if (!function.Method.IsStatic) { //I should really make some presto specific exceptions... i will add that to the todo. throw new Exception("Function is not static"); } //Get a DateTime to mark the beginning of an execution DateTime now = DateTime.Now; string contextID = Generator.RandomAlphaNumeric(Config.UIDLength); //Create a reset event and add it to the dictionary for this job ManualResetEvent mre = new ManualResetEvent(false); waits[contextID] = mre; //add the job to the scheduled jobs outboundJobs[contextID] = callback; //execute SerializationEngine serializer = new SerializationEngine (); byte[] stream = serializer.Serialize(parameter); ClusterProxy.Execute(function.Method.DeclaringType.Assembly.FullName, function.Method.DeclaringType.FullName, function.Method.Name, stream, contextID, Key); return contextID; }
/// <summary> /// A verification response has been returned. /// </summary> /// <param id="state">The state object of the response.</param> private void verificationResponse(ClientState state) { SerializationEngine serializer = new SerializationEngine (); Verification vResponse = (Verification)serializer.Deserialize(state.GetDataArray()); NodeID = vResponse.NodeID; HostName = vResponse.HostName; DPI = vResponse.DPI; CPUCount = vResponse.CPUCount; RunningJobs = vResponse.JobCount; TotalMemory = vResponse.TotalMemory; //make sure the assembly and domain listing is good foreach (string assembly in loadedAssemblies) { if(!loadedAssemblies.Contains(assembly)){ loadedAssemblies.Add(assembly); } } foreach (string domain in loadedDomains) { if (!loadedDomains.Contains(domain)) { loadedDomains.Add(domain); } } }
/// <summary> /// A distributed job has completed succesfully and this is the response. /// </summary> /// <param id="state">The state object of the response.</param> private void returnExecution(ClientState state) { SerializationEngine serializer = new SerializationEngine (); ExecutionResult res = (ExecutionResult)serializer.Deserialize(state.GetDataArray()); DomainManager.ReturnExecution(res); }
/// <summary> /// Deliver an assembly to this node. /// </summary> private void deliverAssembly(string assemblyFullName, byte[] assemblyArray, string domainKey) { if(!HasAssembly(assemblyFullName)){ loadedAssemblies.Add(assemblyFullName); } if (!loadedDomains.Contains(domainKey)) { loadedDomains.Add(domainKey); } //make sure we dont deliver the same assembly to ourselves if (NodeID != ClusterManager.NodeID) { SlaveAssembly slavePackage = new SlaveAssembly(assemblyArray, domainKey, assemblyFullName, ClusterManager.NodeID); SerializationEngine serializer = new SerializationEngine (); client.Write(MessageType.ASSEMBLY_TRANSFER_SLAVE, serializer.Serialize(slavePackage)); assemblyLoadReset.Reset(); } }
/// <summary> /// Send a message to the node with the specified ID. /// </summary> /// <param name="message">The user message struct to be sent.</param> public void SendMessage(UserMessage message) { if (!HasDomain(message.DomainKey)) { //get the assemblies Dictionary<string, byte[]> assemblies = DomainManager.GetDomainAssemblies(message.DomainKey); foreach (KeyValuePair<string, byte[]> assem in assemblies) { deliverAssembly(assem.Key, assem.Value, message.DomainKey); } } assemblyLoadReset.WaitOne(); SerializationEngine serializer = new SerializationEngine (); client.Write(MessageType.USER_MESSAGE, serializer.Serialize(message)); }
/// <summary> /// Trigger an execution on this node. /// </summary> /// <param id="executionContext">The execution context of the job.</param> public bool Execute(ExecutionContext executionContext) { RunningJobs++; //first be sure that this node has the appropriate assembly loaded if (!HasAssembly(executionContext.AssemblyName)) { //get the assembly byte[] assembly = DomainManager.GetAssemblyStream(executionContext.AssemblyName); deliverAssembly(executionContext.AssemblyName, assembly, executionContext.DomainKey); } assemblyLoadReset.WaitOne(); //since we know that the other machine has the assembly loaded we can //serialize the execution context and transport SerializationEngine serializer = new SerializationEngine (); client.Write(MessageType.EXECUTION_BEGIN, serializer.Serialize(executionContext)); return true; }
/// <summary> /// Write the status of the cluster to the console. /// </summary> public static void status() { TcpClient client = new TcpClient(); client.Connect("127.0.0.1", Int32.Parse(Config.GetParameter("SERVER_PORT"))); NetworkStream stream = client.GetStream(); byte[] messageTypeEncoded = ASCIIEncoding.ASCII.GetBytes(MessageType.STATUS_TERMINAL); List<byte> message = new List<byte>(BitConverter.GetBytes((long)(8))); message.AddRange(messageTypeEncoded); stream.Write(message.ToArray(), 0, message.ToArray().Length); byte[] messageSize = new byte[8]; stream.Read(messageSize, 0, 8); long size = BitConverter.ToInt64(messageSize, 0); int sizeInt = (int)size; byte[] dataArray = new byte[sizeInt]; stream.Read(dataArray, 0, sizeInt); List<byte> datas = new List<byte>(dataArray); datas.RemoveRange(0, 8); SerializationEngine serializer = new SerializationEngine(); ServerStatus status = (ServerStatus)serializer.Deserialize(datas.ToArray()); //Console Writes Console.WriteLine("Node Count: " + status.NodeCount); Console.WriteLine("Cluster DPI: " + status.CDPI); Console.WriteLine("Total CPU Count: " + status.CPUCount); Console.WriteLine("Total Memory: " + status.TotalMemory); }
/// <summary> /// Return an execution back into the domain. /// </summary> /// <param name="contextID">The context ID of the execution.</param> /// <param name="nodeID">The node ID where the execution was run.</param> /// <param name="result">The serialized result of the excution.</param> public void ReturnExecution(string contextID, ClusterNode node, byte[] result) { SerializationEngine serializer = new SerializationEngine (); PrestoResult resultObj = (PrestoResult)serializer.Deserialize(result); resultObj.ExecutionNode = node; Cluster.ReturnExecution(contextID, resultObj); }
/// <summary> /// This server needs to verify itself and send back a Verfication object. /// </summary> /// <param id="state">The server state object.</param> private static void verifyResponse(ServerState state) { Transfers.Verification verification = new Transfers.Verification(NodeID, ClusterManager.HostName, DPI.GetDPI(), Memory.GetTotalSize(), CPU.GetCount(), Executor.RunningJobs(), DomainManager.GetAllDomainKeys(), DomainManager.GetAllAssemblyNames()); SerializationEngine serializer = new SerializationEngine (); state.Write(MessageType.VERIFICATION_RESPONSE, serializer.Serialize(verification).ToArray()); }
/// <summary> /// Recieve a user message from a remote node. /// </summary> /// <param name="state">The server state object of this transfer.</param> private static void receiveMessage(ServerState state) { SerializationEngine serializer = new SerializationEngine (); UserMessage message = (UserMessage)serializer.Deserialize(state.GetDataArray()); DomainManager.DeliverMessage(message); }