All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hadoop.mapreduce.task.reduce.Shuffle Maven / Gradle / Ivy

The newest version!
/**
 * 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.hadoop.mapreduce.task.reduce;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocalDirAllocator;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.mapred.Counters;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.RawKeyValueIterator;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.Task;
import org.apache.hadoop.mapred.TaskStatus;
import org.apache.hadoop.mapred.TaskUmbilicalProtocol;
import org.apache.hadoop.mapred.Task.CombineOutputCollector;
import org.apache.hadoop.mapreduce.MRJobConfig;
import org.apache.hadoop.mapreduce.TaskAttemptID;
import org.apache.hadoop.util.Progress;

@InterfaceAudience.Private
@InterfaceStability.Unstable
public class Shuffle implements ExceptionReporter {
  private static final Log LOG = LogFactory.getLog(Shuffle.class);
  private static final int PROGRESS_FREQUENCY = 2000;
  
  private final TaskAttemptID reduceId;
  private final JobConf jobConf;
  private final Reporter reporter;
  private final ShuffleClientMetrics metrics;
  private final TaskUmbilicalProtocol umbilical;
  
  private final ShuffleScheduler scheduler;
  private final MergeManager merger;
  private Throwable throwable = null;
  private String throwingThreadName = null;
  private final Progress copyPhase;
  private final TaskStatus taskStatus;
  private final Task reduceTask; //Used for status updates
  
  public Shuffle(TaskAttemptID reduceId, JobConf jobConf, FileSystem localFS,
                 TaskUmbilicalProtocol umbilical,
                 LocalDirAllocator localDirAllocator,  
                 Reporter reporter,
                 CompressionCodec codec,
                 Class combinerClass,
                 CombineOutputCollector combineCollector,
                 Counters.Counter spilledRecordsCounter,
                 Counters.Counter reduceCombineInputCounter,
                 Counters.Counter shuffledMapsCounter,
                 Counters.Counter reduceShuffleBytes,
                 Counters.Counter failedShuffleCounter,
                 Counters.Counter mergedMapOutputsCounter,
                 TaskStatus status,
                 Progress copyPhase,
                 Progress mergePhase,
                 Task reduceTask) {
    this.reduceId = reduceId;
    this.jobConf = jobConf;
    this.umbilical = umbilical;
    this.reporter = reporter;
    this.metrics = new ShuffleClientMetrics(reduceId, jobConf);
    this.copyPhase = copyPhase;
    this.taskStatus = status;
    this.reduceTask = reduceTask;
    
    scheduler = 
      new ShuffleScheduler(jobConf, status, this, copyPhase, 
                                shuffledMapsCounter, 
                                reduceShuffleBytes, failedShuffleCounter);
    merger = new MergeManager(reduceId, jobConf, localFS, 
                                    localDirAllocator, reporter, codec, 
                                    combinerClass, combineCollector, 
                                    spilledRecordsCounter, 
                                    reduceCombineInputCounter, 
                                    mergedMapOutputsCounter, 
                                    this, mergePhase);
  }

  @SuppressWarnings("unchecked")
  public RawKeyValueIterator run() throws IOException, InterruptedException {
    // Start the map-completion events fetcher thread
    final EventFetcher eventFetcher = 
      new EventFetcher(reduceId, umbilical, scheduler, this);
    eventFetcher.start();
    
    // Start the map-output fetcher threads
    final int numFetchers = jobConf.getInt(MRJobConfig.SHUFFLE_PARALLEL_COPIES, 5);
    Fetcher[] fetchers = new Fetcher[numFetchers];
    for (int i=0; i < numFetchers; ++i) {
      fetchers[i] = new Fetcher(jobConf, reduceId, scheduler, merger, 
                                     reporter, metrics, this, 
                                     reduceTask.getJobTokenSecret());
      fetchers[i].start();
    }
    
    // Wait for shuffle to complete successfully
    while (!scheduler.waitUntilDone(PROGRESS_FREQUENCY)) {
      reporter.progress();
      
      synchronized (this) {
        if (throwable != null) {
          throw new ShuffleError("error in shuffle in " + throwingThreadName,
                                 throwable);
        }
      }
    }

    // Stop the event-fetcher thread
    eventFetcher.interrupt();
    try {
      eventFetcher.join();
    } catch(Throwable t) {
      LOG.info("Failed to stop " + eventFetcher.getName(), t);
    }
    
    // Stop the map-output fetcher threads
    for (Fetcher fetcher : fetchers) {
      fetcher.interrupt();
    }
    for (Fetcher fetcher : fetchers) {
      fetcher.join();
    }
    fetchers = null;
    
    // stop the scheduler
    scheduler.close();

    copyPhase.complete(); // copy is already complete
    taskStatus.setPhase(TaskStatus.Phase.SORT);
    reduceTask.statusUpdate(umbilical);

    // Finish the on-going merges...
    RawKeyValueIterator kvIter = null;
    try {
      kvIter = merger.close();
    } catch (Throwable e) {
      throw new ShuffleError("Error while doing final merge " , e);
    }

    // Sanity check
    synchronized (this) {
      if (throwable != null) {
        throw new ShuffleError("error in shuffle in " + throwingThreadName,
                               throwable);
      }
    }
    
    return kvIter;
  }

  public synchronized void reportException(Throwable t) {
    if (throwable == null) {
      throwable = t;
      throwingThreadName = Thread.currentThread().getName();
      // Notify the scheduler so that the reporting thread finds the 
      // exception immediately.
      synchronized (scheduler) {
        scheduler.notifyAll();
      }
    }
  }
  
  public static class ShuffleError extends IOException {
    private static final long serialVersionUID = 5753909320586607881L;

    ShuffleError(String msg, Throwable t) {
      super(msg, t);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy