/* (c) 2014 LinkedIn Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the * License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. */ package com.linkedin.cubert.plan.physical; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class represents the Logger thread that presents the program status to the user. * * Created by spyne on 9/26/14. */ class LoggerThread extends Thread { final ExecutorService executorService; /* The total number of jobs to execute */ private Integer nJobsToExecute = null; public LoggerThread(ExecutorService executorService) { this.executorService = executorService; } @Override public void run() { try { logProgress(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } private void logProgress() throws IOException, InterruptedException { double lastProgress = 0; while (executorService.execState == ExecutorService.ExecutionState.RUNNING) { // 500 ms is what Pig uses to let hadoop jobs progress before computing // the latest progress Thread.sleep(500); logTrackingURLs(); double newProgress = computeLatestProgress() / nJobsToExecute; if (notifyProgress(newProgress, lastProgress)) { lastProgress = newProgress; } } } private void logTrackingURLs() { synchronized (executorService.jobsToLog) { JobExecutor j; Iterator<JobExecutor> itr = executorService.jobsToLog.iterator(); while (itr.hasNext()) { j = itr.next(); try { String url = j.job.getTrackingURL(); System.out.println("Job: [" + j.job.getJobName() + "], More information at: " + url); itr.remove(); } // job in define state, not yet running, no URL catch (IllegalStateException ignored) {} } } } /* returns value between 0.0 and number of jobs */ private double computeLatestProgress() throws IOException { double retval = 0.0; retval += getSuccessfulJobsSize(); List<JobExecutor> runningJobs = getRunningJobs(); for (JobExecutor runningJob : runningJobs) { retval += progressOfRunningJob(runningJob); } return retval; } private int getSuccessfulJobsSize() throws IOException { int retval = 0; synchronized (executorService.scheduledJobs) { for (JobExecutor scheduledJob : executorService.scheduledJobs) { try { if (scheduledJob.job.isSuccessful()) { retval++; } } catch (IllegalStateException ignored) {} } } return retval; } private List<JobExecutor> getRunningJobs() throws IOException { List<JobExecutor> runningJobs = new ArrayList<JobExecutor>(); synchronized (executorService.scheduledJobs) { for (JobExecutor scheduledJob : executorService.scheduledJobs) { try { if (!scheduledJob.job.isComplete()) { runningJobs.add(scheduledJob); } } catch (IllegalStateException ignored) {} } } return runningJobs; } private double progressOfRunningJob(JobExecutor jobexecutor) throws IOException { double retval = 0.0; try { retval += jobexecutor.job.mapProgress(); if (jobexecutor.hasReducePhase()) { retval += jobexecutor.job.reduceProgress(); retval /= 2; } return retval; } catch (IllegalStateException e) { return 0.0; } } private boolean notifyProgress(double newProgress, double lastProgress) { if (newProgress >= (lastProgress + ExecutorService.PROGRESS_UPDATE)) { int perCom = (int) (newProgress * 100); if (perCom != 100) { System.out.println(perCom + "% complete"); } return true; } return false; } public void setnJobsToExecute(int nJobsToExecute) { this.nJobsToExecute = nJobsToExecute; } }