/// <summary>
        /// Called when node cannot be reached. It's checked by heartbeat time difference.
        /// </summary>
        /// <param name="node">Node object which is unreachable.</param>
        internal void OnNodeUnreachable(Node node)
        {
            Console.WriteLine("[Alert] Node unreachable. node=" + node.ToString());

            //first remove disconnected node
            nodeManager.Logout(node.NodeKey);


        }
        /// <summary>
        /// Process login data and return node instance.
        /// </summary>
        /// <param name="loginData">Login data</param>
        /// <param name="nodeName">Name of node</param>
        /// <param name="nodeIP">Node's IP</param>
        /// <param name="nodePCName">Node's PC name</param>
        /// <param name="priorityKeyData">Priority data. Which is a array of job class name seperated by '>' and '='.  For example, 'EQT>EQT_Quoter=FICC>FICC_TEST=EQT_TEST' means that node will process a job with EQT job class name first. If no job with EQT job class name found, it will find EQT_Quoter or FICC. If nothing found, it will find FICC_TEST or EQT_TEST. If job class has same priority, it is rotate internally so that node can treat job with same priority fairly. </param>
        /// <param name="totalWorkerCount">Number of total worker</param>
        /// <param name="benchmarkRunningTime">Running time of benchmark function in millisecond</param>
        /// <param name="lastProcBinaryVersion">Version of jobs processor binaries.</param>
        /// <param name="nodeBinaryVersion">Version of node binary.</param>
        /// <returns>Return node instance with given login data, return null when fail.</returns>
        public Node Login(string loginData, string nodeName, string nodeIP, string nodePCName, string priorityKeyData, int totalWorkerCount, long benchmarkRunningTime, int lastProcBinaryVersion, int nodeBinaryVersion)
        {
            if (nodeMapByLoginData.ContainsKey(loginData))
                nodeMapByLoginData.Remove(loginData);
            if (!nodeMapByLoginData.ContainsKey(loginData))
            {
                string nodeKey = Guid.NewGuid().ToString();
                Node node = new Node(nodeKey, loginData, nodeName, nodeIP, nodePCName, totalWorkerCount, benchmarkRunningTime, lastProcBinaryVersion, nodeBinaryVersion);
                //error when priorityKeyData failed
                if (node.SetJobClassPriorityData(priorityKeyData))
                    return null;
                nodeMapByLoginData.Add(loginData, node);
                nodeMapByKey.Add(nodeKey, node);
                List<string> jobClassList = node.GetJobClassPriorityList();
                foreach (string jobClassName in jobClassList)
                {
                    Dictionary<string, Node> tmpDic = null;
                    if (!nodeMapMapByClass.ContainsKey(jobClassName))
                    {
                        tmpDic = new Dictionary<string, Node>();
                        nodeMapMapByClass.Add(jobClassName, tmpDic);
                    }
                    else
                    {
                        tmpDic = nodeMapMapByClass[jobClassName];
                    }
                    tmpDic.Add(nodeKey, node);
                }
                return node;
            }
            else
            {
                return null;
            }

        }
 /// <summary>
 /// Update node's job processor with given byte array and version.
 /// </summary>
 /// <param name="node"></param>
 /// <param name="version"></param>
 /// <param name="compressedFile"></param>
 private void UpdateProcBinary(Node node, int version, byte[] compressedFile)
 {
     AsyncServerNodeProcUpdateCastMessage msg = new AsyncServerNodeProcUpdateCastMessage();
     msg.updateVersion = version;
     //msg.compressedFile = compressedFile;
     AsyncMessageSender sender = node.GetAsyncCommSender();
     Task.Factory.StartNew(() =>
     {
         if (!sender.SendCast(msg))
             Console.WriteLine("[Error] SendCast failed!");
     });
 }
 /// <summary>
 /// Update node's job processor with given version and file on the disk wich specified name.
 /// </summary>
 /// <param name="node"></param>
 /// <param name="version"></param>
 /// <returns></returns>
 public bool UpdateProcBinary(Node node, int version)
 {
     string updateFilename = version + ".zip";
     string binaryPath = Path.Combine(Environment.CurrentDirectory, "ProcBinaries");
     string updateFileFullpath = Path.Combine(binaryPath, updateFilename);
     try
     {
         //byte[] compressedFile = File.ReadAllBytes(updateFileFullpath);
         AsyncServerNodeProcUpdateCastMessage msg = new AsyncServerNodeProcUpdateCastMessage();
         msg.updateVersion = version;
         //msg.compressedFile = compressedFile;
         AsyncMessageSender sender = node.GetAsyncCommSender();
         Task.Factory.StartNew(() =>
         {
             if (!sender.SendCast(msg))
                 Console.WriteLine("[Error] SendCast failed!");
         });
         return true;
     }
     catch (FileNotFoundException)
     {
         Console.WriteLine("[Error][NodeManager][UpdateNodeBinary] FIle not found. " + updateFileFullpath);
         return false;
     }
 }
 private void UpdateNodeBinary(Node node, int version, byte[] compressedFile)
 {
     AsyncServerNodeNodeBinUpdateCastMessage msg = new AsyncServerNodeNodeBinUpdateCastMessage();
     msg.updateVersion = version;
     //msg.compressedFile = compressedFile;
     if (!node.GetAsyncCommSender().SendCast(msg))
         Console.WriteLine("[Error] SendCast failed!");
 }
 public int Compare(Node other, string jobClassName)
 {
     return (int)(this.GetPerformanceFactor(jobClassName) - other.GetPerformanceFactor(jobClassName));
 }