/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. See the License for the * specific language governing permissions and limitations * under the License. */ package com.aliyun.odps.mapred.bridge; import java.io.IOException; import java.io.PrintStream; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import com.alibaba.fastjson.JSON; import com.aliyun.odps.Instance; import com.aliyun.odps.Instance.StageProgress; import com.aliyun.odps.Instance.Status; import com.aliyun.odps.Instance.TaskStatus; import com.aliyun.odps.Instance.TaskSummary; import com.aliyun.odps.OdpsException; import com.aliyun.odps.commons.util.CostResultParser; import com.aliyun.odps.counter.CounterGroup; import com.aliyun.odps.counter.Counters; import com.aliyun.odps.mapred.EventListener; import com.aliyun.odps.mapred.JobStatus; import com.aliyun.odps.mapred.RunningJob; import com.aliyun.odps.mapred.conf.SessionState; import com.aliyun.odps.udf.utils.CounterUtils; public class BridgeRunningJob implements RunningJob { protected Instance instance; protected JobStatus state = JobStatus.PREP; protected Counters counters = new Counters(); protected String diagnostics = ""; protected boolean stopped = false; private long timeMark = 0; private boolean hasPrintSummary = false; private boolean hasPrintResult = false; private float mapProgress = 0; private float reduceProgress = 0; private final String taskName; private EventListener event = null; private boolean isCountersOk = true; private boolean isCostMode = false; public BridgeRunningJob(Instance instance, String taskName, EventListener event) { this.instance = instance; this.taskName = taskName; this.event = event; // print logview url to stdout startUp(); } @Override public String getInstanceID() { return instance.getId(); } @Override public boolean isComplete() { if (isFinished()) { return true; } updateStatus(); return isFinished(); } @Override public boolean isSuccessful() { if (isFinished()) { return (state == JobStatus.SUCCEEDED); } updateStatus(); return (state == JobStatus.SUCCEEDED); } @Override public void waitForCompletion() { int sleeptime = 1000; while (!isComplete()) { try { Thread.sleep(sleeptime); } catch (InterruptedException e) { throw new RuntimeException(e); } sleeptime = ((sleeptime + 500) > 4000) ? 4000 : sleeptime + 500; } // Clean event.onComplete(); } private void startUp() { try { String log = SessionState.get().getOdps().logview().generateLogView(instance, 7 * 24); System.out.println(log); } catch (Exception e) { // do nothing if not load logview class } } @Override public JobStatus getJobStatus() { if (isFinished()) { return state; } updateStatus(); return state; } @Override public void killJob() { stopped = true; try { instance.stop(); } catch (OdpsException ex) { throw new RuntimeException("Kill job Failed", ex); } // Clean event.onComplete(); } @Override public Counters getCounters() { if (!isCountersOk) { throw new RuntimeException("Get Counters Failed!"); } return counters; } @Override public String getDiagnostics() { return diagnostics; } protected boolean isFinished() { return (state == JobStatus.FAILED) || (state == JobStatus.SUCCEEDED) || (state == JobStatus.KILLED); } protected void updateStatus() { try { Status instanceStatus = instance.getStatus(); if (instanceStatus == Status.RUNNING || instanceStatus == Status.SUSPENDED) { state = JobStatus.RUNNING; } else if (instanceStatus == Status.TERMINATED) { TaskStatus taskStatus = instance.getTaskStatus().values().iterator().next(); switch (taskStatus.getStatus()) { case WAITING: case RUNNING: case FAILED: state = JobStatus.FAILED; break; case SUCCESS: state = JobStatus.SUCCEEDED; break; case CANCELLED: state = JobStatus.KILLED; break; default: throw new OdpsException("Got Unknown task status: " + taskStatus.getStatus()); } } else { throw new OdpsException("Got unknown instance status '" + instanceStatus + "'"); } // try to print process information if (needPrintProcess() || isFinished()) { printProgress(); } } catch (OdpsException ex) { throw new RuntimeException(ex); } if (isFinished()) { try { printSummaryAndCollectCounters(); printResult(); } catch (Exception ex) { isCountersOk = false; System.out.println("Get summary failed."); } } } private boolean needPrintProcess() { long now = System.currentTimeMillis(); long interval = 5 * 1000; if (now - timeMark > interval) { timeMark = now; return true; } return false; } /** * Print job progress. * * @throws IOException * @throws OdpsException * if get task progress failed */ private void printProgress() throws OdpsException { PrintStream out = System.out; List<StageProgress> stages = null; stages = instance.getTaskProgress(taskName); if (stages != null && stages.size() != 0) { out.print(Instance.getStageProgressFormattedString(stages)); int mappers = 0; int reducers = 0; mapProgress = 0; reduceProgress = 0; for (StageProgress stage : stages) { int totalWorkers = stage.getTotalWorkers(); if (stage.getName().startsWith("M")) { mappers += totalWorkers; mapProgress += stage.getFinishedPercentage()/100.0 * totalWorkers; } else { reducers += totalWorkers; reduceProgress += stage.getFinishedPercentage()/100.0 * totalWorkers; } } mapProgress = mappers == 0 ? 0 : mapProgress/mappers; reduceProgress = reducers == 0 ? 0 : reduceProgress/reducers; } else { out.print("..."); } out.print('\r'); out.flush(); } @SuppressWarnings({"rawtypes"}) private void printSummaryAndCollectCounters() throws IOException { if (hasPrintSummary || !isSuccessful()) { return; } TaskSummary taskSummary = null; try { taskSummary = instance.getTaskSummary(taskName); } catch (OdpsException ex) { throw new IOException("Get summary encounter error: ", ex); } if (taskSummary == null) { if (System.getProperty("omit.taskstatus.failure", "false").equalsIgnoreCase("true")) { System.out.println("No summary in place."); return; } else { throw new IOException("No summary in place."); } } Map tasks = (Map) taskSummary.get("Stages"); Counters tmpCounters; for (Object e : tasks.values()) { Map task = (Map) e; Map countersValue = (Map) task.get("UserCounters"); if (countersValue != null) { tmpCounters = CounterUtils.createFromJsonString(JSON.toJSONString(countersValue)); Iterator<CounterGroup> iter = tmpCounters.iterator(); while (iter.hasNext()) { if (iter.next().getName().equals("ODPS_SDK_FRAMEWORK_COUNTER_GROUP")) { // ignore framework counter group iter.remove(); } } counters.incrAllCounters(tmpCounters); } } System.out.println(taskSummary.getSummaryText()); System.out.println(counters); hasPrintSummary = true; } private void printResult() throws IOException { if (!hasPrintResult) { try { Map<String, String> m = instance.getTaskResults(); diagnostics = m.values().iterator().next(); if (state == JobStatus.SUCCEEDED) { if (!StringUtils.isEmpty(diagnostics)) { if (isCostMode) { diagnostics = CostResultParser.parse(diagnostics, "MapReduce"); } System.err.println(diagnostics); } System.err.println("OK"); } else { if (!StringUtils.isEmpty(diagnostics)) { System.err.println("FAILED: " + diagnostics); } else { System.err.println("ERROR: " + state.toString()); } } hasPrintResult = true; } catch (Exception ex) { throw new IOException("Get result encounter error: " + ex.getMessage()); } } } @Override public float mapProgress() throws IOException { if (isSuccessful()) { return 1f; } return this.mapProgress; } @Override public float reduceProgress() throws IOException { if (isSuccessful()) { return 1f; } return this.reduceProgress; } public boolean isCostMode() { return isCostMode; } public void setIsCostMode(boolean isCostMode) { this.isCostMode = isCostMode; } }