Skip to content
66 changes: 7 additions & 59 deletions core/src/main/scala/org/apache/spark/MapOutputTracker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ private[spark] abstract class MapOutputTracker(conf: SparkConf) extends Logging
// For testing
def getMapSizesByExecutorId(shuffleId: Int, reduceId: Int)
: Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])] = {
getMapSizesByExecutorId(shuffleId, reduceId, reduceId + 1)
getMapSizesByExecutorId(shuffleId, mapStatus => (0, mapStatus.length), reduceId, reduceId + 1)

@dongjoon-hyun dongjoon-hyun Jun 23, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since mapStatus => (0, mapStatus.length) seems to be used frequently, do you think we can define this function somewhere to prevent mistakes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, sounds good.

}

/**
Expand All @@ -336,28 +336,11 @@ private[spark] abstract class MapOutputTracker(conf: SparkConf) extends Logging
*/
def getMapSizesByExecutorId(
Comment thread
cloud-fan marked this conversation as resolved.
shuffleId: Int,
mapIndexRange: Array[MapStatus] => (Int, Int),
startPartition: Int,
endPartition: Int)
: Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])]
Comment thread
Ngone51 marked this conversation as resolved.
Outdated

/**
* Called from executors to get the server URIs and output sizes for each shuffle block that
* needs to be read from a given range of map output partitions (startPartition is included but
* endPartition is excluded from the range) and is produced by
* a range of mappers (startMapIndex, endMapIndex, startMapIndex is included and
* the endMapIndex is excluded).
Comment thread
Ngone51 marked this conversation as resolved.
*
* @return A sequence of 2-item tuples, where the first item in the tuple is a BlockManagerId,
* and the second item is a sequence of (shuffle block id, shuffle block size, map index)
* tuples describing the shuffle blocks that are stored at that block manager.
*/
def getMapSizesByRange(
shuffleId: Int,
startMapIndex: Int,
endMapIndex: Int,
startPartition: Int,
endPartition: Int): Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])]

/**
* Deletes map output status information for the specified shuffle stage.
*/
Expand Down Expand Up @@ -738,32 +721,15 @@ private[spark] class MapOutputTrackerMaster(
// This method is only called in local-mode.
def getMapSizesByExecutorId(
shuffleId: Int,
mapIndexRange: Array[MapStatus] => (Int, Int),
startPartition: Int,
endPartition: Int)
: Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])] = {
: Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])] = {
Comment thread
Ngone51 marked this conversation as resolved.
Outdated
logDebug(s"Fetching outputs for shuffle $shuffleId, partitions $startPartition-$endPartition")
shuffleStatuses.get(shuffleId) match {
case Some (shuffleStatus) =>
Comment thread
Ngone51 marked this conversation as resolved.
Outdated
shuffleStatus.withMapStatuses { statuses =>
MapOutputTracker.convertMapStatuses(
shuffleId, startPartition, endPartition, statuses, 0, shuffleStatus.mapStatuses.length)
}
case None =>
Iterator.empty
}
}

override def getMapSizesByRange(
shuffleId: Int,
startMapIndex: Int,
endMapIndex: Int,
startPartition: Int,
endPartition: Int): Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])] = {
logDebug(s"Fetching outputs for shuffle $shuffleId, mappers $startMapIndex-$endMapIndex" +
s"partitions $startPartition-$endPartition")
shuffleStatuses.get(shuffleId) match {
case Some(shuffleStatus) =>
shuffleStatus.withMapStatuses { statuses =>
val (startMapIndex, endMapIndex) = mapIndexRange(statuses)
MapOutputTracker.convertMapStatuses(
shuffleId, startPartition, endPartition, statuses, startMapIndex, endMapIndex)
}
Expand Down Expand Up @@ -801,32 +767,14 @@ private[spark] class MapOutputTrackerWorker(conf: SparkConf) extends MapOutputTr
// Get blocks sizes by executor Id. Note that zero-sized blocks are excluded in the result.
override def getMapSizesByExecutorId(
shuffleId: Int,
mapIndexRange: Array[MapStatus] => (Int, Int),
startPartition: Int,
endPartition: Int)
: Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])] = {
Comment thread
Ngone51 marked this conversation as resolved.
Outdated
logDebug(s"Fetching outputs for shuffle $shuffleId, partitions $startPartition-$endPartition")
val statuses = getStatuses(shuffleId, conf)
try {
MapOutputTracker.convertMapStatuses(
shuffleId, startPartition, endPartition, statuses, 0, statuses.length)
} catch {
case e: MetadataFetchFailedException =>
// We experienced a fetch failure so our mapStatuses cache is outdated; clear it:
mapStatuses.clear()
throw e
}
}

override def getMapSizesByRange(
shuffleId: Int,
startMapIndex: Int,
endMapIndex: Int,
startPartition: Int,
endPartition: Int): Iterator[(BlockManagerId, Seq[(BlockId, Long, Int)])] = {
logDebug(s"Fetching outputs for shuffle $shuffleId, mappers $startMapIndex-$endMapIndex" +
s"partitions $startPartition-$endPartition")
val statuses = getStatuses(shuffleId, conf)
try {
val (startMapIndex, endMapIndex) = mapIndexRange(statuses)
MapOutputTracker.convertMapStatuses(
shuffleId, startPartition, endPartition, statuses, startMapIndex, endMapIndex)
} catch {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ class CoGroupedRDD[K: ClassTag](
val metrics = context.taskMetrics().createTempShuffleReadMetrics()
val it = SparkEnv.get.shuffleManager
.getReader(
shuffleDependency.shuffleHandle, split.index, split.index + 1, context, metrics)
shuffleDependency.shuffleHandle,
mapStatus => (0, mapStatus.length),
split.index, split.index + 1, context, metrics)
.read()
rddIterators += ((it, depNum))
}
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/org/apache/spark/rdd/ShuffledRDD.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ class ShuffledRDD[K: ClassTag, V: ClassTag, C: ClassTag](
val dep = dependencies.head.asInstanceOf[ShuffleDependency[K, V, C]]
val metrics = context.taskMetrics().createTempShuffleReadMetrics()
SparkEnv.get.shuffleManager.getReader(
dep.shuffleHandle, split.index, split.index + 1, context, metrics)
dep.shuffleHandle, mapStatus => (0, mapStatus.length),
split.index, split.index + 1, context, metrics)
.read()
.asInstanceOf[Iterator[(K, C)]]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ private[spark] class SubtractedRDD[K: ClassTag, V: ClassTag, W: ClassTag](
val iter = SparkEnv.get.shuffleManager
.getReader(
shuffleDependency.shuffleHandle,
mapStatus => (0, mapStatus.length),
partition.index,
partition.index + 1,
context,
Expand Down
19 changes: 4 additions & 15 deletions core/src/main/scala/org/apache/spark/shuffle/ShuffleManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.spark.shuffle

import org.apache.spark.{ShuffleDependency, TaskContext}
import org.apache.spark.scheduler.MapStatus

/**
* Pluggable interface for shuffle systems. A ShuffleManager is created in SparkEnv on the driver
Expand All @@ -43,26 +44,14 @@ private[spark] trait ShuffleManager {
context: TaskContext,
metrics: ShuffleWriteMetricsReporter): ShuffleWriter[K, V]

/**
* Get a reader for a range of reduce partitions (startPartition to endPartition-1, inclusive).
* Called on executors by reduce tasks.
*/
def getReader[K, C](
Comment thread
Ngone51 marked this conversation as resolved.
handle: ShuffleHandle,
startPartition: Int,
endPartition: Int,
context: TaskContext,
metrics: ShuffleReadMetricsReporter): ShuffleReader[K, C]

/**
* Get a reader for a range of reduce partitions (startPartition to endPartition-1, inclusive) to
* read from map output (startMapIndex to endMapIndex - 1, inclusive).
* read from map output which specified by mapIndexRange.
* Called on executors by reduce tasks.
*/
def getReaderForRange[K, C](
def getReader[K, C](
handle: ShuffleHandle,
startMapIndex: Int,
endMapIndex: Int,
mapIndexRange: Array[MapStatus] => (Int, Int),
Comment thread
Ngone51 marked this conversation as resolved.
Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with the parameters of startPartition and endPartition, here we can remain the startMapIndex and endMapIndex in getReader method. It will be more clearly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is we can not know the endMapIndex at the caller side. Maybe we could try @cloud-fan 's suggestion above.

startPartition: Int,
endPartition: Int,
context: TaskContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import scala.collection.JavaConverters._

import org.apache.spark._
import org.apache.spark.internal.{config, Logging}
import org.apache.spark.scheduler.MapStatus
import org.apache.spark.shuffle._
import org.apache.spark.shuffle.api.{ShuffleDataIO, ShuffleExecutorComponents}
import org.apache.spark.util.Utils
Expand Down Expand Up @@ -120,27 +121,13 @@ private[spark] class SortShuffleManager(conf: SparkConf) extends ShuffleManager
*/
override def getReader[K, C](
handle: ShuffleHandle,
mapIndexRange: Array[MapStatus] => (Int, Int),
startPartition: Int,
endPartition: Int,
context: TaskContext,
metrics: ShuffleReadMetricsReporter): ShuffleReader[K, C] = {
val blocksByAddress = SparkEnv.get.mapOutputTracker.getMapSizesByExecutorId(
handle.shuffleId, startPartition, endPartition)
new BlockStoreShuffleReader(
handle.asInstanceOf[BaseShuffleHandle[K, _, C]], blocksByAddress, context, metrics,
shouldBatchFetch = canUseBatchFetch(startPartition, endPartition, context))
}

override def getReaderForRange[K, C](
handle: ShuffleHandle,
startMapIndex: Int,
endMapIndex: Int,
startPartition: Int,
endPartition: Int,
context: TaskContext,
metrics: ShuffleReadMetricsReporter): ShuffleReader[K, C] = {
val blocksByAddress = SparkEnv.get.mapOutputTracker.getMapSizesByRange(
handle.shuffleId, startMapIndex, endMapIndex, startPartition, endPartition)
handle.shuffleId, mapIndexRange, startPartition, endPartition)
new BlockStoreShuffleReader(
handle.asInstanceOf[BaseShuffleHandle[K, _, C]], blocksByAddress, context, metrics,
shouldBatchFetch = canUseBatchFetch(startPartition, endPartition, context))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class MapOutputTrackerSuite extends SparkFunSuite {
tracker.registerMapOutput(10, 1, MapStatus(BlockManagerId("b", "hostB", 1000),
Array(size10000, size0, size1000, size0), 6))
assert(tracker.containsShuffle(10))
assert(tracker.getMapSizesByExecutorId(10, 0, 4).toSeq ===
assert(tracker.getMapSizesByExecutorId(10, _ => (0, 2), 0, 4).toSeq ===
Seq(
(BlockManagerId("a", "hostA", 1000),
Seq((ShuffleBlockId(10, 5, 1), size1000, 0),
Expand Down
3 changes: 2 additions & 1 deletion core/src/test/scala/org/apache/spark/ShuffleSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,8 @@ abstract class ShuffleSuite extends SparkFunSuite with Matchers with LocalSparkC
val taskContext = new TaskContextImpl(
1, 0, 0, 2L, 0, taskMemoryManager, new Properties, metricsSystem)
val metrics = taskContext.taskMetrics.createTempShuffleReadMetrics()
val reader = manager.getReader[Int, Int](shuffleHandle, 0, 1, taskContext, metrics)
val reader = manager.getReader[Int, Int](shuffleHandle, mapStatus => (0, mapStatus.length),
0, 1, taskContext, metrics)
TaskContext.unset()
val readData = reader.read().toIndexedSeq
assert(readData === data1.toIndexedSeq || readData === data2.toIndexedSeq)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ class CustomShuffledRDD[K, V, C](
val part = p.asInstanceOf[CustomShuffledRDDPartition]
val metrics = context.taskMetrics().createTempShuffleReadMetrics()
SparkEnv.get.shuffleManager.getReader(
dependency.shuffleHandle, part.startIndexInParent, part.endIndexInParent, context, metrics)
dependency.shuffleHandle, mapStatus => (0, mapStatus.length), part.startIndexInParent,
part.endIndexInParent, context, metrics)
.read()
.asInstanceOf[Iterator[(K, C)]]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class BlockStoreShuffleReaderSuite extends SparkFunSuite with LocalSparkContext
// shuffle data to read.
val mapOutputTracker = mock(classOf[MapOutputTracker])
when(mapOutputTracker.getMapSizesByExecutorId(
shuffleId, reduceId, reduceId + 1)).thenReturn {
shuffleId, null, reduceId, reduceId + 1)).thenReturn {
// Test a scenario where all data is local, to avoid creating a bunch of additional mocks
// for the code to read data over the network.
val shuffleBlockIdsAndSizes = (0 until numMaps).map { mapId =>
Expand Down Expand Up @@ -132,7 +132,7 @@ class BlockStoreShuffleReaderSuite extends SparkFunSuite with LocalSparkContext
val taskContext = TaskContext.empty()
val metrics = taskContext.taskMetrics.createTempShuffleReadMetrics()
val blocksByAddress = mapOutputTracker.getMapSizesByExecutorId(
shuffleId, reduceId, reduceId + 1)
shuffleId, null, reduceId, reduceId + 1)
val shuffleReader = new BlockStoreShuffleReader(
shuffleHandle,
blocksByAddress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,26 +185,25 @@ class ShuffledRowRDD(
case CoalescedPartitionSpec(startReducerIndex, endReducerIndex) =>
SparkEnv.get.shuffleManager.getReader(
dependency.shuffleHandle,
mapStatus => (0, mapStatus.length),
startReducerIndex,
endReducerIndex,
context,
sqlMetricsReporter)

case PartialReducerPartitionSpec(reducerIndex, startMapIndex, endMapIndex, _) =>
SparkEnv.get.shuffleManager.getReaderForRange(
SparkEnv.get.shuffleManager.getReader(
dependency.shuffleHandle,
startMapIndex,
endMapIndex,
_ => (startMapIndex, endMapIndex),
reducerIndex,
reducerIndex + 1,
context,
sqlMetricsReporter)

case PartialMapperPartitionSpec(mapIndex, startReducerIndex, endReducerIndex) =>
SparkEnv.get.shuffleManager.getReaderForRange(
SparkEnv.get.shuffleManager.getReader(
dependency.shuffleHandle,
mapIndex,
mapIndex + 1,
_ => (mapIndex, mapIndex + 1),
startReducerIndex,
endReducerIndex,
context,
Expand Down