/// <summary> /// The C# worker process is used to execute only one JVM Task. It will exit after the task is finished. /// </summary> private static void RunSimpleWorker() { try { InitializeLogger(); logger.LogInfo("RunSimpleWorker ..."); PrintFiles(); int javaPort = int.Parse(Console.ReadLine()); //reading port number written from JVM logger.LogDebug("Port number used to pipe in/out data between JVM and CLR {0}", javaPort); Socket socket = InitializeSocket(javaPort); TaskRunner taskRunner = new TaskRunner(0, socket, false); taskRunner.Run(); } catch (Exception e) { logger.LogError("RunSimpleWorker failed with exception, will Exit"); logger.LogException(e); Environment.Exit(-1); } logger.LogInfo("RunSimpleWorker finished successfully"); }
/// <summary> /// Listen to the server socket and accept new TCP connection from JVM side. Then create new TaskRunner instance and /// add it to waitingTaskRunners queue. /// </summary> private void StartDaemonServer(TcpListener listener) { logger.LogInfo("StartDaemonServer ..."); bool sparkReuseWorker = false; string envVar = Environment.GetEnvironmentVariable("SPARK_REUSE_WORKER"); // this envVar is set in JVM side if ((envVar != null) && envVar.Equals("1")) { sparkReuseWorker = true; } try { int trId = 1; int workThreadNum = 0; while (true) { Socket socket = listener.AcceptSocket(); logger.LogInfo("Connection accepted for taskRunnerId: {0}", trId); using (NetworkStream s = new NetworkStream(socket)) { SerDe.Write(s, trId); // write taskRunnerId to JVM side s.Flush(); } TaskRunner taskRunner = new TaskRunner(trId, socket, sparkReuseWorker); waitingTaskRunners.Add(taskRunner); taskRunnerRegistry[trId] = taskRunner; trId++; int taskRunnerNum = taskRunnerRegistry.Count(); while (workThreadNum < taskRunnerNum) // launch new work thread as appropriate { // start threads that do the actual work of running tasks, there are several options here: // Option 1. TPL - Task Parallel Library // Option 2. ThreadPool // Option 3. Self managed threads group // Option 3 is selected after testing in real cluster because it can get the best performance. // When using option 1 or 2, it is observered that the boot time may be as large as 50 ~ 60s. // But it is always less than 1s for option 3. Perhaps this is because TPL and ThreadPool are not // suitable for long running threads. new Thread(FetchAndRun).Start(); workThreadNum++; } } } catch (Exception e) { logger.LogError("StartDaemonServer exception, will exit"); logger.LogException(e); Environment.Exit(-1); } }
public void Run() { try { // start TCP listening server var listener = SocketFactory.CreateSocket(); listener.Listen(); // get the local port and write it back to JVM side IPEndPoint endPoint = (IPEndPoint)listener.LocalEndPoint; int localPort = endPoint.Port; byte[] bytes = SerDe.ToBytes(localPort); Stream outputStream = Console.OpenStandardOutput(); outputStream.Write(bytes, 0, sizeof(int)); // can not initialize logger earlier to avoid unwanted stdout ouput InitializeLogger(); logger.LogInfo("Run MultiThreadWorker ..."); logger.LogDebug("Port number used to pipe in/out data between JVM and CLR {0}", localPort); Worker.PrintFiles(); // start daemon server to listen to socket new Thread(() => { StartDaemonServer(listener); }).Start(); // read from JVM via pipe, stop TaskRunner according to instruction from JVM side Stream inputStream = Console.OpenStandardInput(); while (true) { int length = inputStream.Read(bytes, 0, sizeof(int)); if (length != sizeof(int)) { logger.LogError("Read error, length: {0}, will exit", length); Environment.Exit(-1); } int trId = SerDe.ToInt(bytes); if (trId < 0) { // This branch is used in Unit test to stop MultiThreadServer logger.LogInfo("receive negative trId: {0}, will exit", trId); Environment.Exit(0); } else { logger.LogInfo("try to stop taskRunner [{0}]", trId); if (taskRunnerRegistry.ContainsKey(trId)) { TaskRunner tr = taskRunnerRegistry[trId]; tr.Stop(); } else { logger.LogWarn("can't find taskRunner [{0}] in TaskRunnerRegistery. Maybe it has exited already?", trId); } } } } catch (Exception e) { logger.LogError("RunDaemonWorker exception, will Exit"); logger.LogException(e); Environment.Exit(-1); } }