/** * 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 org.apache.ambari.log4j.hadoop.mapreduce.jobhistory; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ambari.eventdb.model.WorkflowContext; import org.apache.ambari.eventdb.model.WorkflowDag; import org.apache.ambari.eventdb.model.WorkflowDag.WorkflowDagEntry; import org.apache.ambari.log4j.common.LogStoreUpdateProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.mapreduce.Counter; import org.apache.hadoop.mapreduce.CounterGroup; import org.apache.hadoop.mapreduce.Counters; import org.apache.hadoop.mapreduce.TaskType; import org.apache.hadoop.tools.rumen.HistoryEvent; import org.apache.hadoop.tools.rumen.JhCounter; import org.apache.hadoop.tools.rumen.JhCounterGroup; import org.apache.hadoop.tools.rumen.JhCounters; import org.apache.hadoop.tools.rumen.JobFinishedEvent; import org.apache.hadoop.tools.rumen.JobInfoChangeEvent; import org.apache.hadoop.tools.rumen.JobInitedEvent; import org.apache.hadoop.tools.rumen.JobStatusChangedEvent; import org.apache.hadoop.tools.rumen.JobSubmittedEvent; import org.apache.hadoop.tools.rumen.JobUnsuccessfulCompletionEvent; import org.apache.hadoop.tools.rumen.MapAttemptFinishedEvent; import org.apache.hadoop.tools.rumen.ReduceAttemptFinishedEvent; import org.apache.hadoop.tools.rumen.TaskAttemptFinishedEvent; import org.apache.hadoop.tools.rumen.TaskAttemptStartedEvent; import org.apache.hadoop.tools.rumen.TaskAttemptUnsuccessfulCompletionEvent; import org.apache.hadoop.tools.rumen.TaskFailedEvent; import org.apache.hadoop.tools.rumen.TaskFinishedEvent; import org.apache.hadoop.tools.rumen.TaskStartedEvent; import org.apache.hadoop.util.StringUtils; import org.apache.log4j.spi.LoggingEvent; import org.codehaus.jackson.map.ObjectMapper; public class MapReduceJobHistoryUpdater implements LogStoreUpdateProvider { private static final Log LOG = LogFactory.getLog(MapReduceJobHistoryUpdater.class); private Connection connection; private static final String WORKFLOW_TABLE = "workflow"; private static final String JOB_TABLE = "job"; private static final String TASK_TABLE = "task"; private static final String TASKATTEMPT_TABLE = "taskAttempt"; private PreparedStatement workflowPS = null; private PreparedStatement workflowSelectPS = null; private PreparedStatement workflowUpdateTimePS = null; private PreparedStatement workflowUpdateNumCompletedPS = null; private Map<Class<? extends HistoryEvent>, PreparedStatement> entitySqlMap = new HashMap<Class<? extends HistoryEvent>, PreparedStatement>(); @Override public void init(Connection connection) throws IOException { this.connection = connection; try { initializePreparedStatements(); } catch (SQLException sqle) { throw new IOException(sqle); } } private void initializePreparedStatements() throws SQLException { initializeJobPreparedStatements(); initializeTaskPreparedStatements(); initializeTaskAttemptPreparedStatements(); } private PreparedStatement jobEndUpdate; private void initializeJobPreparedStatements() throws SQLException { /** * Job events */ // JobSubmittedEvent PreparedStatement jobSubmittedPrepStmnt = connection.prepareStatement( "INSERT INTO " + JOB_TABLE + " (" + "jobId, " + "jobName, " + "userName, " + "confPath, " + "queue, " + "submitTime, " + "workflowId, " + "workflowEntityName " + ") " + "VALUES" + " (?, ?, ?, ?, ?, ?, ?, ?)" ); entitySqlMap.put(JobSubmittedEvent.class, jobSubmittedPrepStmnt); workflowSelectPS = connection.prepareStatement( "SELECT workflowContext FROM " + WORKFLOW_TABLE + " where workflowId = ?" ); workflowPS = connection.prepareStatement( "INSERT INTO " + WORKFLOW_TABLE + " (" + "workflowId, " + "workflowName, " + "workflowContext, " + "userName, " + "startTime, " + "lastUpdateTime, " + "duration, " + "numJobsTotal, " + "numJobsCompleted" + ") " + "VALUES" + " (?, ?, ?, ?, ?, ?, 0, ?, 0)" ); workflowUpdateTimePS = connection.prepareStatement( "UPDATE " + WORKFLOW_TABLE + " SET " + "workflowContext = ?, " + "numJobsTotal = ?, " + "lastUpdateTime = ?, " + "duration = ? - startTime " + "WHERE workflowId = ?" ); workflowUpdateNumCompletedPS = connection.prepareStatement( "UPDATE " + WORKFLOW_TABLE + " SET " + "lastUpdateTime = ?, " + "duration = ? - startTime, " + "numJobsCompleted = (" + "SELECT count(*)" + " FROM " + JOB_TABLE + " WHERE " + "workflowId = " + WORKFLOW_TABLE + ".workflowId" + " AND status = 'SUCCESS'), " + "inputBytes = (" + "SELECT sum(inputBytes)" + " FROM " + JOB_TABLE + " WHERE " + "workflowId = " + WORKFLOW_TABLE + ".workflowId" + " AND status = 'SUCCESS'), " + "outputBytes = (" + "SELECT sum(outputBytes)" + " FROM " + JOB_TABLE + " WHERE " + "workflowId = " + WORKFLOW_TABLE + ".workflowId" + " AND status = 'SUCCESS') " + " WHERE workflowId = (SELECT workflowId FROM " + JOB_TABLE + " WHERE jobId = ?)" ); // JobFinishedEvent PreparedStatement jobFinishedPrepStmnt = connection.prepareStatement( "UPDATE " + JOB_TABLE + " SET " + "finishTime = ?, " + "finishedMaps = ?, " + "finishedReduces= ?, " + "failedMaps = ?, " + "failedReduces = ?, " + "inputBytes = ?, " + "outputBytes = ? " + "WHERE " + "jobId = ?" ); entitySqlMap.put(JobFinishedEvent.class, jobFinishedPrepStmnt); // JobInitedEvent PreparedStatement jobInitedPrepStmnt = connection.prepareStatement( "UPDATE " + JOB_TABLE + " SET " + "launchTime = ?, " + "maps = ?, " + "reduces = ?, " + "status = ? "+ "WHERE " + "jobId = ?" ); entitySqlMap.put(JobInitedEvent.class, jobInitedPrepStmnt); // JobStatusChangedEvent PreparedStatement jobStatusChangedPrepStmnt = connection.prepareStatement( "UPDATE " + JOB_TABLE + " SET " + "status = ? "+ "WHERE " + "jobId = ?" ); entitySqlMap.put(JobStatusChangedEvent.class, jobStatusChangedPrepStmnt); // JobInfoChangedEvent PreparedStatement jobInfoChangedPrepStmnt = connection.prepareStatement( "UPDATE " + JOB_TABLE + " SET " + "submitTime = ?, " + "launchTime = ? " + "WHERE " + "jobId = ?" ); entitySqlMap.put(JobInfoChangeEvent.class, jobInfoChangedPrepStmnt); // JobUnsuccessfulCompletionEvent PreparedStatement jobUnsuccessfulPrepStmnt = connection.prepareStatement( "UPDATE " + JOB_TABLE + " SET " + "finishTime = ?, " + "finishedMaps = ?, " + "finishedReduces = ?, " + "status = ? " + "WHERE " + "jobId = ?" ); entitySqlMap.put( JobUnsuccessfulCompletionEvent.class, jobUnsuccessfulPrepStmnt); // Job update at the end jobEndUpdate = connection.prepareStatement( "UPDATE " + JOB_TABLE + " SET " + " mapsRuntime = (" + "SELECT " + "SUM(" + TASKATTEMPT_TABLE + ".finishTime" + " - " + TASKATTEMPT_TABLE + ".startTime" + ")" + " FROM " + TASKATTEMPT_TABLE + " WHERE " + TASKATTEMPT_TABLE + ".jobId = " + JOB_TABLE + ".jobId " + " AND " + TASKATTEMPT_TABLE + ".taskType = ?)" + ", " + " reducesRuntime = (" + "SELECT SUM(" + TASKATTEMPT_TABLE + ".finishTime" + " - " + TASKATTEMPT_TABLE + ".startTime" + ")" + " FROM " + TASKATTEMPT_TABLE + " WHERE " + TASKATTEMPT_TABLE + ".jobId = " + JOB_TABLE + ".jobId " + " AND " + TASKATTEMPT_TABLE + ".taskType = ?) " + " WHERE " + "jobId = ?" ); } private void initializeTaskPreparedStatements() throws SQLException { /** * Task events */ // TaskStartedEvent PreparedStatement taskStartedPrepStmnt = connection.prepareStatement( "INSERT INTO " + TASK_TABLE + " (" + "jobId, " + "taskType, " + "splits, " + "startTime, " + "taskId" + ") " + "VALUES (?, ?, ?, ?, ?)" ); entitySqlMap.put(TaskStartedEvent.class, taskStartedPrepStmnt); // TaskFinishedEvent PreparedStatement taskFinishedPrepStmnt = connection.prepareStatement( "UPDATE " + TASK_TABLE + " SET " + "jobId = ?, " + "taskType = ?, " + "status = ?, " + "finishTime = ? " + " WHERE " + "taskId = ?" ); entitySqlMap.put(TaskFinishedEvent.class, taskFinishedPrepStmnt); // TaskFailedEvent PreparedStatement taskFailedPrepStmnt = connection.prepareStatement( "UPDATE " + TASK_TABLE + " SET " + "jobId = ?, " + "taskType = ?, " + "status = ?, " + "finishTime = ?, " + "error = ?, " + "failedAttempt = ? " + "WHERE " + "taskId = ?" ); entitySqlMap.put(TaskFailedEvent.class, taskFailedPrepStmnt); } private void initializeTaskAttemptPreparedStatements() throws SQLException { /** * TaskAttempt events */ // TaskAttemptStartedEvent PreparedStatement taskAttemptStartedPrepStmnt = connection.prepareStatement( "INSERT INTO " + TASKATTEMPT_TABLE + " (" + "jobId, " + "taskId, " + "taskType, " + "startTime, " + "taskTracker, " + "locality, " + "avataar, " + "taskAttemptId" + ") " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)" ); entitySqlMap.put( TaskAttemptStartedEvent.class, taskAttemptStartedPrepStmnt); // TaskAttemptFinishedEvent PreparedStatement taskAttemptFinishedPrepStmnt = connection.prepareStatement( "UPDATE " + TASKATTEMPT_TABLE + " SET " + "jobId = ?, " + "taskId = ?, " + "taskType = ?, " + "finishTime = ?, " + "status = ?, " + "taskTracker = ? " + " WHERE " + "taskAttemptId = ?" ); entitySqlMap.put( TaskAttemptFinishedEvent.class, taskAttemptFinishedPrepStmnt); // TaskAttemptUnsuccessfulEvent PreparedStatement taskAttemptUnsuccessfulPrepStmnt = connection.prepareStatement( "UPDATE " + TASKATTEMPT_TABLE + " SET " + "jobId = ?, " + "taskId = ?, " + "taskType = ?, " + "finishTime = ?, " + "status = ?, " + "taskTracker = ?, " + "error = ? " + " WHERE " + "taskAttemptId = ?" ); entitySqlMap.put( TaskAttemptUnsuccessfulCompletionEvent.class, taskAttemptUnsuccessfulPrepStmnt); // MapAttemptFinishedEvent PreparedStatement mapAttemptFinishedPrepStmnt = connection.prepareStatement( "UPDATE " + TASKATTEMPT_TABLE + " SET " + "jobId = ?, " + "taskId = ?, " + "taskType = ?, " + "mapFinishTime = ?, " + "finishTime = ?, " + "inputBytes = ?, " + "outputBytes = ?, " + "status = ?, " + "taskTracker = ? " + " WHERE " + "taskAttemptId = ?" ); entitySqlMap.put( MapAttemptFinishedEvent.class, mapAttemptFinishedPrepStmnt); // ReduceAttemptFinishedEvent PreparedStatement reduceAttemptFinishedPrepStmnt = connection.prepareStatement( "UPDATE " + TASKATTEMPT_TABLE + " SET " + "jobId = ?, " + "taskId = ?, " + "taskType = ?, " + "shuffleFinishTime = ?, " + "sortFinishTime = ?, " + "finishTime = ?, " + "inputBytes = ?, " + "outputBytes = ?, " + "status = ?, " + "taskTracker = ? " + " WHERE " + "taskAttemptId = ?" ); entitySqlMap.put( ReduceAttemptFinishedEvent.class, reduceAttemptFinishedPrepStmnt); } private void doUpdates(LoggingEvent originalEvent, Object parsedEvent) throws SQLException { Class<?> eventClass = parsedEvent.getClass(); PreparedStatement entityPS = entitySqlMap.get(eventClass); if (entityPS == null) { LOG.debug("No prepared statement for " + eventClass); return; } if (eventClass == JobSubmittedEvent.class) { processJobSubmittedEvent(entityPS, workflowSelectPS, workflowPS, workflowUpdateTimePS, originalEvent, (JobSubmittedEvent)parsedEvent); } else if (eventClass == JobFinishedEvent.class) { processJobFinishedEvent(entityPS, workflowUpdateNumCompletedPS, originalEvent, (JobFinishedEvent)parsedEvent); } else if (eventClass == JobInitedEvent.class){ processJobInitedEvent(entityPS, originalEvent, (JobInitedEvent)parsedEvent); } else if (eventClass == JobStatusChangedEvent.class) { processJobStatusChangedEvent(entityPS, originalEvent, (JobStatusChangedEvent)parsedEvent); } else if (eventClass == JobInfoChangeEvent.class) { processJobInfoChangeEvent(entityPS, originalEvent, (JobInfoChangeEvent)parsedEvent); } else if (eventClass == JobUnsuccessfulCompletionEvent.class) { processJobUnsuccessfulEvent(entityPS, originalEvent, (JobUnsuccessfulCompletionEvent)parsedEvent); } else if (eventClass == TaskStartedEvent.class) { processTaskStartedEvent(entityPS, originalEvent, (TaskStartedEvent)parsedEvent); } else if (eventClass == TaskFinishedEvent.class) { processTaskFinishedEvent(entityPS, originalEvent, (TaskFinishedEvent)parsedEvent); } else if (eventClass == TaskFailedEvent.class) { processTaskFailedEvent(entityPS, originalEvent, (TaskFailedEvent)parsedEvent); } else if (eventClass == TaskAttemptStartedEvent.class) { processTaskAttemptStartedEvent(entityPS, originalEvent, (TaskAttemptStartedEvent)parsedEvent); } else if (eventClass == TaskAttemptFinishedEvent.class) { processTaskAttemptFinishedEvent(entityPS, originalEvent, (TaskAttemptFinishedEvent)parsedEvent); } else if (eventClass == TaskAttemptUnsuccessfulCompletionEvent.class) { processTaskAttemptUnsuccessfulEvent(entityPS, originalEvent, (TaskAttemptUnsuccessfulCompletionEvent)parsedEvent); } else if (eventClass == MapAttemptFinishedEvent.class) { processMapAttemptFinishedEvent(entityPS, originalEvent, (MapAttemptFinishedEvent)parsedEvent); } else if (eventClass == ReduceAttemptFinishedEvent.class) { processReduceAttemptFinishedEvent(entityPS, originalEvent, (ReduceAttemptFinishedEvent)parsedEvent); } } private void updateJobStatsAtFinish(String jobId) { try { jobEndUpdate.setString(1, "MAP"); jobEndUpdate.setString(2, "REDUCE"); jobEndUpdate.setString(3, jobId); jobEndUpdate.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to update mapsRuntime/reducesRuntime for " + jobId, sqle); } } private static WorkflowContext generateWorkflowContext( JobSubmittedEvent historyEvent) { WorkflowDag wfDag = new WorkflowDag(); WorkflowDagEntry wfDagEntry = new WorkflowDagEntry(); wfDagEntry.setSource("X"); wfDag.addEntry(wfDagEntry); WorkflowContext wc = new WorkflowContext(); wc.setWorkflowId(historyEvent.getJobId().toString().replace("job_", "mr_")); wc.setWorkflowName(historyEvent.getJobName()); wc.setWorkflowEntityName("X"); wc.setWorkflowDag(wfDag); return wc; } // this is based on the regex in org.apache.hadoop.tools.rumen.ParsedLine // except this assumes the format "key"="value" so that both key and value // are quoted and may contain escaped characters private static final Pattern adjPattern = Pattern.compile("\"([^\"\\\\]*+(?:\\\\.[^\"\\\\]*+)*+)\"" + "=" + "\"([^\"\\\\]*+(?:\\\\.[^\"\\\\]*+)*+)\" "); public static WorkflowContext buildWorkflowContext(JobSubmittedEvent historyEvent) { String workflowId = historyEvent.getWorkflowId() .replace("\\", ""); if (workflowId.isEmpty()) return generateWorkflowContext(historyEvent); String workflowName = historyEvent.getWorkflowName() .replace("\\", ""); String workflowNodeName = historyEvent.getWorkflowNodeName() .replace("\\", ""); String workflowAdjacencies = StringUtils.unEscapeString( historyEvent.getWorkflowAdjacencies(), StringUtils.ESCAPE_CHAR, new char[] {'"', '=', '.'}); WorkflowContext context = new WorkflowContext(); context.setWorkflowId(workflowId); context.setWorkflowName(workflowName); context.setWorkflowEntityName(workflowNodeName); WorkflowDag dag = new WorkflowDag(); Matcher matcher = adjPattern.matcher(workflowAdjacencies); while(matcher.find()){ WorkflowDagEntry dagEntry = new WorkflowDagEntry(); dagEntry.setSource(matcher.group(1).replace("\\", "")); String[] values = StringUtils.getStrings( matcher.group(2).replace("\\", "")); if (values != null) { for (String target : values) { dagEntry.addTarget(target); } } dag.addEntry(dagEntry); } if (dag.getEntries().isEmpty()) { WorkflowDagEntry wfDagEntry = new WorkflowDagEntry(); wfDagEntry.setSource(workflowNodeName); dag.addEntry(wfDagEntry); } context.setWorkflowDag(dag); return context; } public static void mergeEntries(Map<String, Set<String>> edges, List<WorkflowDagEntry> entries) { if (entries == null) return; for (WorkflowDagEntry entry : entries) { if (!edges.containsKey(entry.getSource())) edges.put(entry.getSource(), new TreeSet<String>()); Set<String> targets = edges.get(entry.getSource()); targets.addAll(entry.getTargets()); } } public static WorkflowDag constructMergedDag(WorkflowContext workflowContext, WorkflowContext existingWorkflowContext) { Map<String, Set<String>> edges = new TreeMap<String, Set<String>>(); if (existingWorkflowContext.getWorkflowDag() != null) mergeEntries(edges, existingWorkflowContext.getWorkflowDag().getEntries()); if (workflowContext.getWorkflowDag() != null) mergeEntries(edges, workflowContext.getWorkflowDag().getEntries()); WorkflowDag mergedDag = new WorkflowDag(); for (Entry<String,Set<String>> edge : edges.entrySet()) { WorkflowDagEntry entry = new WorkflowDagEntry(); entry.setSource(edge.getKey()); entry.getTargets().addAll(edge.getValue()); mergedDag.addEntry(entry); } return mergedDag; } private static WorkflowContext getSanitizedWorkflow(WorkflowContext workflowContext, WorkflowContext existingWorkflowContext) { WorkflowContext sanitizedWC = new WorkflowContext(); if (existingWorkflowContext == null) { sanitizedWC.setWorkflowDag(workflowContext.getWorkflowDag()); sanitizedWC.setParentWorkflowContext(workflowContext.getParentWorkflowContext()); } else { sanitizedWC.setWorkflowDag(constructMergedDag(existingWorkflowContext, workflowContext)); sanitizedWC.setParentWorkflowContext(existingWorkflowContext.getParentWorkflowContext()); } return sanitizedWC; } private static String getWorkflowString(WorkflowContext sanitizedWC) { String sanitizedWCString = null; try { ObjectMapper om = new ObjectMapper(); sanitizedWCString = om.writeValueAsString(sanitizedWC); } catch (IOException e) { e.printStackTrace(); sanitizedWCString = ""; } return sanitizedWCString; } private void processJobSubmittedEvent( PreparedStatement jobPS, PreparedStatement workflowSelectPS, PreparedStatement workflowPS, PreparedStatement workflowUpdateTimePS, LoggingEvent logEvent, JobSubmittedEvent historyEvent) { try { String jobId = historyEvent.getJobId().toString(); jobPS.setString(1, jobId); jobPS.setString(2, historyEvent.getJobName()); jobPS.setString(3, historyEvent.getUserName()); jobPS.setString(4, historyEvent.getJobConfPath()); jobPS.setString(5, historyEvent.getJobQueueName()); jobPS.setLong(6, historyEvent.getSubmitTime()); WorkflowContext workflowContext = buildWorkflowContext(historyEvent); // Get workflow information boolean insertWorkflow = false; String existingContextString = null; ResultSet rs = null; try { workflowSelectPS.setString(1, workflowContext.getWorkflowId()); workflowSelectPS.execute(); rs = workflowSelectPS.getResultSet(); if (rs.next()) { existingContextString = rs.getString(1); } else { insertWorkflow = true; } } catch (SQLException sqle) { LOG.warn("workflow select failed with: ", sqle); insertWorkflow = false; } finally { try { if (rs != null) rs.close(); } catch (SQLException e) { LOG.error("Exception while closing ResultSet", e); } } // Insert workflow if (insertWorkflow) { workflowPS.setString(1, workflowContext.getWorkflowId()); workflowPS.setString(2, workflowContext.getWorkflowName()); workflowPS.setString(3, getWorkflowString(getSanitizedWorkflow(workflowContext, null))); workflowPS.setString(4, historyEvent.getUserName()); workflowPS.setLong(5, historyEvent.getSubmitTime()); workflowPS.setLong(6, historyEvent.getSubmitTime()); workflowPS.setLong(7, workflowContext.getWorkflowDag().size()); workflowPS.executeUpdate(); LOG.debug("Successfully inserted workflowId = " + workflowContext.getWorkflowId()); } else { ObjectMapper om = new ObjectMapper(); WorkflowContext existingWorkflowContext = null; try { if (existingContextString != null) existingWorkflowContext = om.readValue(existingContextString.getBytes(), WorkflowContext.class); } catch (IOException e) { LOG.warn("Couldn't read existing workflow context for " + workflowContext.getWorkflowId(), e); } WorkflowContext sanitizedWC = getSanitizedWorkflow(workflowContext, existingWorkflowContext); workflowUpdateTimePS.setString(1, getWorkflowString(sanitizedWC)); workflowUpdateTimePS.setLong(2, sanitizedWC.getWorkflowDag().size()); workflowUpdateTimePS.setLong(3, historyEvent.getSubmitTime()); workflowUpdateTimePS.setLong(4, historyEvent.getSubmitTime()); workflowUpdateTimePS.setString(5, workflowContext.getWorkflowId()); workflowUpdateTimePS.executeUpdate(); LOG.debug("Successfully updated workflowId = " + workflowContext.getWorkflowId()); } // Insert job jobPS.setString(7, workflowContext.getWorkflowId()); jobPS.setString(8, workflowContext.getWorkflowEntityName()); jobPS.executeUpdate(); LOG.debug("Successfully inserted job = " + jobId + " and workflowId = " + workflowContext.getWorkflowId()); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobId() + " into " + JOB_TABLE, sqle); } catch (Exception e) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobId() + " into " + JOB_TABLE, e); } } private void processJobFinishedEvent( PreparedStatement entityPS, PreparedStatement workflowUpdateNumCompletedPS, LoggingEvent logEvent, JobFinishedEvent historyEvent) { Counters counters = historyEvent.getMapCounters(); long inputBytes = 0; if (counters != null) { for (CounterGroup group : counters) { for (Counter counter : group) { if (counter.getName().equals("HDFS_BYTES_READ")) inputBytes += counter.getValue(); } } } if (historyEvent.getFinishedReduces() != 0) counters = historyEvent.getReduceCounters(); long outputBytes = 0; if (counters != null) { for (CounterGroup group : counters) { for (Counter counter : group) { if (counter.getName().equals("HDFS_BYTES_WRITTEN")) outputBytes += counter.getValue(); } } } try { entityPS.setLong(1, historyEvent.getFinishTime()); entityPS.setInt(2, historyEvent.getFinishedMaps()); entityPS.setInt(3, historyEvent.getFinishedReduces()); entityPS.setInt(4, historyEvent.getFailedMaps()); entityPS.setInt(5, historyEvent.getFailedReduces()); entityPS.setLong(6, inputBytes); entityPS.setLong(7, outputBytes); entityPS.setString(8, historyEvent.getJobid().toString()); entityPS.executeUpdate(); // job finished events always have success status workflowUpdateNumCompletedPS.setLong(1, historyEvent.getFinishTime()); workflowUpdateNumCompletedPS.setLong(2, historyEvent.getFinishTime()); workflowUpdateNumCompletedPS.setString(3, historyEvent.getJobid().toString()); workflowUpdateNumCompletedPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobid() + " into " + JOB_TABLE, sqle); } updateJobStatsAtFinish(historyEvent.getJobid().toString()); } private void processJobInitedEvent( PreparedStatement entityPS, LoggingEvent logEvent, JobInitedEvent historyEvent) { try { entityPS.setLong(1, historyEvent.getLaunchTime()); entityPS.setInt(2, historyEvent.getTotalMaps()); entityPS.setInt(3, historyEvent.getTotalReduces()); entityPS.setString(4, historyEvent.getStatus()); entityPS.setString(5, historyEvent.getJobId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobId() + " into " + JOB_TABLE, sqle); } } private void processJobStatusChangedEvent( PreparedStatement entityPS, LoggingEvent logEvent, JobStatusChangedEvent historyEvent) { try { entityPS.setString(1, historyEvent.getStatus()); entityPS.setString(2, historyEvent.getJobId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobId() + " into " + JOB_TABLE, sqle); } } private void processJobInfoChangeEvent( PreparedStatement entityPS, LoggingEvent logEvent, JobInfoChangeEvent historyEvent) { try { entityPS.setLong(1, historyEvent.getSubmitTime()); entityPS.setLong(2, historyEvent.getLaunchTime()); entityPS.setString(3, historyEvent.getJobId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobId() + " into " + JOB_TABLE, sqle); } } private void processJobUnsuccessfulEvent( PreparedStatement entityPS, LoggingEvent logEvent, JobUnsuccessfulCompletionEvent historyEvent) { try { entityPS.setLong(1, historyEvent.getFinishTime()); entityPS.setLong(2, historyEvent.getFinishedMaps()); entityPS.setLong(3, historyEvent.getFinishedReduces()); entityPS.setString(4, historyEvent.getStatus()); entityPS.setString(5, historyEvent.getJobId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for job " + historyEvent.getJobId() + " into " + JOB_TABLE, sqle); } updateJobStatsAtFinish(historyEvent.getJobId().toString()); } private void processTaskStartedEvent(PreparedStatement entityPS, LoggingEvent logEvent, TaskStartedEvent historyEvent) { try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskType().toString()); entityPS.setString(3, historyEvent.getSplitLocations()); entityPS.setLong(4, historyEvent.getStartTime()); entityPS.setString(5, historyEvent.getTaskId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for task " + historyEvent.getTaskId() + " into " + TASK_TABLE, sqle); } } private void processTaskFinishedEvent( PreparedStatement entityPS, LoggingEvent logEvent, TaskFinishedEvent historyEvent) { try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskType().toString()); entityPS.setString(3, historyEvent.getTaskStatus()); entityPS.setLong(4, historyEvent.getFinishTime()); entityPS.setString(5, historyEvent.getTaskId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for task " + historyEvent.getTaskId() + " into " + TASK_TABLE, sqle); } } private void processTaskFailedEvent( PreparedStatement entityPS, LoggingEvent logEvent, TaskFailedEvent historyEvent) { try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskType().toString()); entityPS.setString(3, historyEvent.getTaskStatus()); entityPS.setLong(4, historyEvent.getFinishTime()); entityPS.setString(5, historyEvent.getError()); if (historyEvent.getFailedAttemptID() != null) { entityPS.setString(6, historyEvent.getFailedAttemptID().toString()); } else { entityPS.setString(6, "task_na"); } entityPS.setString(7, historyEvent.getTaskId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for task " + historyEvent.getTaskId() + " into " + TASK_TABLE, sqle); } } private void processTaskAttemptStartedEvent( PreparedStatement entityPS, LoggingEvent logEvent, TaskAttemptStartedEvent historyEvent) { try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskId().toString()); entityPS.setString(3, historyEvent.getTaskType().toString()); entityPS.setLong(4, historyEvent.getStartTime()); entityPS.setString(5, historyEvent.getTrackerName()); entityPS.setString(6, historyEvent.getLocality().toString()); entityPS.setString(7, historyEvent.getAvataar().toString()); entityPS.setString(8, historyEvent.getTaskAttemptId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for taskAttempt " + historyEvent.getTaskAttemptId() + " into " + TASKATTEMPT_TABLE, sqle); } } private void processTaskAttemptFinishedEvent( PreparedStatement entityPS, LoggingEvent logEvent, TaskAttemptFinishedEvent historyEvent) { if (historyEvent.getTaskType() == TaskType.MAP || historyEvent.getTaskType() == TaskType.REDUCE) { LOG.debug("Ignoring TaskAttemptFinishedEvent for " + historyEvent.getTaskType()); return; } try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskId().toString()); entityPS.setString(3, historyEvent.getTaskType().toString()); entityPS.setLong(4, historyEvent.getFinishTime()); entityPS.setString(5, historyEvent.getTaskStatus()); entityPS.setString(6, historyEvent.getHostname()); entityPS.setString(7, historyEvent.getAttemptId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for taskAttempt " + historyEvent.getAttemptId() + " into " + TASKATTEMPT_TABLE, sqle); } } private void processTaskAttemptUnsuccessfulEvent( PreparedStatement entityPS, LoggingEvent logEvent, TaskAttemptUnsuccessfulCompletionEvent historyEvent) { try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskId().toString()); entityPS.setString(3, historyEvent.getTaskType().toString()); entityPS.setLong(4, historyEvent.getFinishTime()); entityPS.setString(5, historyEvent.getTaskStatus()); entityPS.setString(6, historyEvent.getHostname()); entityPS.setString(7, historyEvent.getError()); entityPS.setString(8, historyEvent.getTaskAttemptId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for taskAttempt " + historyEvent.getTaskAttemptId() + " into " + TASKATTEMPT_TABLE, sqle); } } private void processMapAttemptFinishedEvent( PreparedStatement entityPS, LoggingEvent logEvent, MapAttemptFinishedEvent historyEvent) { if (historyEvent.getTaskType() != TaskType.MAP) { LOG.debug("Ignoring MapAttemptFinishedEvent for " + historyEvent.getTaskType()); return; } long[] ioBytes = getInputOutputBytes(historyEvent.getCounters()); try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskId().toString()); entityPS.setString(3, historyEvent.getTaskType().toString()); entityPS.setLong(4, historyEvent.getMapFinishTime()); entityPS.setLong(5, historyEvent.getFinishTime()); entityPS.setLong(6, ioBytes[0]); entityPS.setLong(7, ioBytes[1]); entityPS.setString(8, historyEvent.getTaskStatus()); entityPS.setString(9, historyEvent.getHostname()); entityPS.setString(10, historyEvent.getAttemptId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for taskAttempt " + historyEvent.getAttemptId() + " into " + TASKATTEMPT_TABLE, sqle); } } private void processReduceAttemptFinishedEvent( PreparedStatement entityPS, LoggingEvent logEvent, ReduceAttemptFinishedEvent historyEvent) { if (historyEvent.getTaskType() != TaskType.REDUCE) { LOG.debug("Ignoring ReduceAttemptFinishedEvent for " + historyEvent.getTaskType()); return; } long[] ioBytes = getInputOutputBytes(historyEvent.getCounters()); try { entityPS.setString(1, historyEvent.getTaskId().getJobID().toString()); entityPS.setString(2, historyEvent.getTaskId().toString()); entityPS.setString(3, historyEvent.getTaskType().toString()); entityPS.setLong(4, historyEvent.getShuffleFinishTime()); entityPS.setLong(5, historyEvent.getSortFinishTime()); entityPS.setLong(6, historyEvent.getFinishTime()); entityPS.setLong(7, ioBytes[0]); entityPS.setLong(8, ioBytes[1]); entityPS.setString(9, historyEvent.getTaskStatus()); entityPS.setString(10, historyEvent.getHostname()); entityPS.setString(11, historyEvent.getAttemptId().toString()); entityPS.executeUpdate(); } catch (SQLException sqle) { LOG.info("Failed to store " + historyEvent.getEventType() + " for taskAttempt " + historyEvent.getAttemptId() + " into " + TASKATTEMPT_TABLE, sqle); } } public static long[] getInputOutputBytes(JhCounters counters) { long inputBytes = 0; long outputBytes = 0; if (counters != null) { for (JhCounterGroup counterGroup : counters.groups) { if (counterGroup.name.equals("FileSystemCounters")) { for (JhCounter counter : counterGroup.counts) { if (counter.name.equals("HDFS_BYTES_READ") || counter.name.equals("FILE_BYTES_READ")) inputBytes += counter.value; else if (counter.name.equals("HDFS_BYTES_WRITTEN") || counter.name.equals("FILE_BYTES_WRITTEN")) outputBytes += counter.value; } } } } return new long[]{inputBytes, outputBytes}; } @Override public void update(LoggingEvent originalEvent, Object parsedEvent) throws IOException { try { doUpdates(originalEvent, parsedEvent); } catch (SQLException sqle) { throw new IOException(sqle); } } }