Skip to content

Commit f403826

Browse files
committed
Merge branch 'master' into iterator-to-disk
2 parents 81d670c + dfd40e9 commit f403826

File tree

11 files changed

+59
-84
lines changed

11 files changed

+59
-84
lines changed

core/src/main/scala/org/apache/spark/SparkContext.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ class SparkContext(
246246
taskScheduler.start()
247247

248248
@volatile private[spark] var dagScheduler = new DAGScheduler(taskScheduler)
249-
dagScheduler.start()
250249

251250
ui.start()
252251

core/src/main/scala/org/apache/spark/rdd/HadoopRDD.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private[spark] class HadoopPartition(rddId: Int, idx: Int, @transient s: InputSp
5252
* sources in HBase, or S3).
5353
*
5454
* @param sc The SparkContext to associate the RDD with.
55-
* @param broadCastedConf A general Hadoop Configuration, or a subclass of it. If the enclosed
55+
* @param broadcastedConf A general Hadoop Configuration, or a subclass of it. If the enclosed
5656
* variabe references an instance of JobConf, then that JobConf will be used for the Hadoop job.
5757
* Otherwise, a new JobConf will be created on each slave using the enclosed Configuration.
5858
* @param initLocalJobConfFuncOpt Optional closure used to initialize any JobConf that HadoopRDD

core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala

Lines changed: 40 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ package org.apache.spark.scheduler
1919

2020
import java.io.NotSerializableException
2121
import java.util.Properties
22-
import java.util.concurrent.{LinkedBlockingQueue, TimeUnit}
2322
import java.util.concurrent.atomic.AtomicInteger
2423

24+
import akka.actor._
25+
import akka.util.duration._
2526
import scala.collection.mutable.{ArrayBuffer, HashMap, HashSet, Map}
2627

2728
import org.apache.spark._
@@ -65,12 +66,12 @@ class DAGScheduler(
6566

6667
// Called by TaskScheduler to report task's starting.
6768
def taskStarted(task: Task[_], taskInfo: TaskInfo) {
68-
eventQueue.put(BeginEvent(task, taskInfo))
69+
eventProcessActor ! BeginEvent(task, taskInfo)
6970
}
7071

7172
// Called to report that a task has completed and results are being fetched remotely.
7273
def taskGettingResult(task: Task[_], taskInfo: TaskInfo) {
73-
eventQueue.put(GettingResultEvent(task, taskInfo))
74+
eventProcessActor ! GettingResultEvent(task, taskInfo)
7475
}
7576

7677
// Called by TaskScheduler to report task completions or failures.
@@ -81,23 +82,23 @@ class DAGScheduler(
8182
accumUpdates: Map[Long, Any],
8283
taskInfo: TaskInfo,
8384
taskMetrics: TaskMetrics) {
84-
eventQueue.put(CompletionEvent(task, reason, result, accumUpdates, taskInfo, taskMetrics))
85+
eventProcessActor ! CompletionEvent(task, reason, result, accumUpdates, taskInfo, taskMetrics)
8586
}
8687

8788
// Called by TaskScheduler when an executor fails.
8889
def executorLost(execId: String) {
89-
eventQueue.put(ExecutorLost(execId))
90+
eventProcessActor ! ExecutorLost(execId)
9091
}
9192

9293
// Called by TaskScheduler when a host is added
9394
def executorGained(execId: String, host: String) {
94-
eventQueue.put(ExecutorGained(execId, host))
95+
eventProcessActor ! ExecutorGained(execId, host)
9596
}
9697

9798
// Called by TaskScheduler to cancel an entire TaskSet due to either repeated failures or
9899
// cancellation of the job itself.
99100
def taskSetFailed(taskSet: TaskSet, reason: String) {
100-
eventQueue.put(TaskSetFailed(taskSet, reason))
101+
eventProcessActor ! TaskSetFailed(taskSet, reason)
101102
}
102103

103104
// The time, in millis, to wait for fetch failure events to stop coming in after one is detected;
@@ -109,7 +110,30 @@ class DAGScheduler(
109110
// resubmit failed stages
110111
val POLL_TIMEOUT = 10L
111112

112-
private val eventQueue = new LinkedBlockingQueue[DAGSchedulerEvent]
113+
private val eventProcessActor: ActorRef = env.actorSystem.actorOf(Props(new Actor {
114+
override def preStart() {
115+
context.system.scheduler.schedule(RESUBMIT_TIMEOUT milliseconds, RESUBMIT_TIMEOUT milliseconds) {
116+
if (failed.size > 0) {
117+
resubmitFailedStages()
118+
}
119+
}
120+
}
121+
122+
/**
123+
* The main event loop of the DAG scheduler, which waits for new-job / task-finished / failure
124+
* events and responds by launching tasks. This runs in a dedicated thread and receives events
125+
* via the eventQueue.
126+
*/
127+
def receive = {
128+
case event: DAGSchedulerEvent =>
129+
logDebug("Got event of type " + event.getClass.getName)
130+
131+
if (!processEvent(event))
132+
submitWaitingStages()
133+
else
134+
context.stop(self)
135+
}
136+
}))
113137

114138
private[scheduler] val nextJobId = new AtomicInteger(0)
115139

@@ -150,16 +174,6 @@ class DAGScheduler(
150174

151175
val metadataCleaner = new MetadataCleaner(MetadataCleanerType.DAG_SCHEDULER, this.cleanup)
152176

153-
// Start a thread to run the DAGScheduler event loop
154-
def start() {
155-
new Thread("DAGScheduler") {
156-
setDaemon(true)
157-
override def run() {
158-
DAGScheduler.this.run()
159-
}
160-
}.start()
161-
}
162-
163177
def addSparkListener(listener: SparkListener) {
164178
listenerBus.addListener(listener)
165179
}
@@ -301,8 +315,7 @@ class DAGScheduler(
301315
assert(partitions.size > 0)
302316
val func2 = func.asInstanceOf[(TaskContext, Iterator[_]) => _]
303317
val waiter = new JobWaiter(this, jobId, partitions.size, resultHandler)
304-
eventQueue.put(JobSubmitted(jobId, rdd, func2, partitions.toArray, allowLocal, callSite,
305-
waiter, properties))
318+
eventProcessActor ! JobSubmitted(jobId, rdd, func2, partitions.toArray, allowLocal, callSite, waiter, properties)
306319
waiter
307320
}
308321

@@ -337,8 +350,7 @@ class DAGScheduler(
337350
val func2 = func.asInstanceOf[(TaskContext, Iterator[_]) => _]
338351
val partitions = (0 until rdd.partitions.size).toArray
339352
val jobId = nextJobId.getAndIncrement()
340-
eventQueue.put(JobSubmitted(jobId, rdd, func2, partitions, allowLocal = false, callSite,
341-
listener, properties))
353+
eventProcessActor ! JobSubmitted(jobId, rdd, func2, partitions, allowLocal = false, callSite, listener, properties)
342354
listener.awaitResult() // Will throw an exception if the job fails
343355
}
344356

@@ -347,19 +359,19 @@ class DAGScheduler(
347359
*/
348360
def cancelJob(jobId: Int) {
349361
logInfo("Asked to cancel job " + jobId)
350-
eventQueue.put(JobCancelled(jobId))
362+
eventProcessActor ! JobCancelled(jobId)
351363
}
352364

353365
def cancelJobGroup(groupId: String) {
354366
logInfo("Asked to cancel job group " + groupId)
355-
eventQueue.put(JobGroupCancelled(groupId))
367+
eventProcessActor ! JobGroupCancelled(groupId)
356368
}
357369

358370
/**
359371
* Cancel all jobs that are running or waiting in the queue.
360372
*/
361373
def cancelAllJobs() {
362-
eventQueue.put(AllJobsCancelled)
374+
eventProcessActor ! AllJobsCancelled
363375
}
364376

365377
/**
@@ -474,42 +486,6 @@ class DAGScheduler(
474486
}
475487
}
476488

477-
478-
/**
479-
* The main event loop of the DAG scheduler, which waits for new-job / task-finished / failure
480-
* events and responds by launching tasks. This runs in a dedicated thread and receives events
481-
* via the eventQueue.
482-
*/
483-
private def run() {
484-
SparkEnv.set(env)
485-
486-
while (true) {
487-
val event = eventQueue.poll(POLL_TIMEOUT, TimeUnit.MILLISECONDS)
488-
if (event != null) {
489-
logDebug("Got event of type " + event.getClass.getName)
490-
}
491-
this.synchronized { // needed in case other threads makes calls into methods of this class
492-
if (event != null) {
493-
if (processEvent(event)) {
494-
return
495-
}
496-
}
497-
498-
val time = System.currentTimeMillis() // TODO: use a pluggable clock for testability
499-
// Periodically resubmit failed stages if some map output fetches have failed and we have
500-
// waited at least RESUBMIT_TIMEOUT. We wait for this short time because when a node fails,
501-
// tasks on many other nodes are bound to get a fetch failure, and they won't all get it at
502-
// the same time, so we want to make sure we've identified all the reduce tasks that depend
503-
// on the failed node.
504-
if (failed.size > 0 && time > lastFetchFailureTime + RESUBMIT_TIMEOUT) {
505-
resubmitFailedStages()
506-
} else {
507-
submitWaitingStages()
508-
}
509-
}
510-
}
511-
}
512-
513489
/**
514490
* Run a job on an RDD locally, assuming it has only a single partition and no dependencies.
515491
* We run the operation in a separate thread just in case it takes a bunch of time, so that we
@@ -878,15 +854,15 @@ class DAGScheduler(
878854
// If the RDD has narrow dependencies, pick the first partition of the first narrow dep
879855
// that has any placement preferences. Ideally we would choose based on transfer sizes,
880856
// but this will do for now.
881-
rdd.dependencies.foreach(_ match {
857+
rdd.dependencies.foreach {
882858
case n: NarrowDependency[_] =>
883859
for (inPart <- n.getParents(partition)) {
884860
val locs = getPreferredLocs(n.rdd, inPart)
885861
if (locs != Nil)
886862
return locs
887863
}
888864
case _ =>
889-
})
865+
}
890866
Nil
891867
}
892868

@@ -909,7 +885,7 @@ class DAGScheduler(
909885
}
910886

911887
def stop() {
912-
eventQueue.put(StopDAGScheduler)
888+
eventProcessActor ! StopDAGScheduler
913889
metadataCleaner.cancel()
914890
taskSched.stop()
915891
}

core/src/main/scala/org/apache/spark/scheduler/cluster/ClusterTaskSetManager.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.spark.scheduler.cluster
1919

20+
import java.io.NotSerializableException
2021
import java.util.Arrays
2122

2223
import scala.collection.mutable.ArrayBuffer
@@ -484,6 +485,14 @@ private[spark] class ClusterTaskSetManager(
484485

485486
case ef: ExceptionFailure =>
486487
sched.dagScheduler.taskEnded(tasks(index), ef, null, null, info, ef.metrics.getOrElse(null))
488+
if (ef.className == classOf[NotSerializableException].getName()) {
489+
// If the task result wasn't serializable, there's no point in trying to re-execute it.
490+
logError("Task %s:%s had a not serializable result: %s; not retrying".format(
491+
taskSet.id, index, ef.description))
492+
abort("Task %s:%s had a not serializable result: %s".format(
493+
taskSet.id, index, ef.description))
494+
return
495+
}
487496
val key = ef.description
488497
val now = clock.getTime()
489498
val (printFull, dupCount) = {

core/src/main/scala/org/apache/spark/scheduler/cluster/SimrSchedulerBackend.scala

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ private[spark] class SimrSchedulerBackend(
3131
val tmpPath = new Path(driverFilePath + "_tmp")
3232
val filePath = new Path(driverFilePath)
3333

34-
val uiFilePath = driverFilePath + "_ui"
35-
val tmpUiPath = new Path(uiFilePath + "_tmp")
36-
val uiPath = new Path(uiFilePath)
37-
3834
val maxCores = System.getProperty("spark.simr.executor.cores", "1").toInt
3935

4036
override def start() {
@@ -49,23 +45,17 @@ private[spark] class SimrSchedulerBackend(
4945

5046
logInfo("Writing to HDFS file: " + driverFilePath)
5147
logInfo("Writing Akka address: " + driverUrl)
52-
logInfo("Writing to HDFS file: " + uiFilePath)
5348
logInfo("Writing Spark UI Address: " + sc.ui.appUIAddress)
5449

5550
// Create temporary file to prevent race condition where executors get empty driverUrl file
5651
val temp = fs.create(tmpPath, true)
5752
temp.writeUTF(driverUrl)
5853
temp.writeInt(maxCores)
54+
temp.writeUTF(sc.ui.appUIAddress)
5955
temp.close()
6056

6157
// "Atomic" rename
6258
fs.rename(tmpPath, filePath)
63-
64-
// Write Spark UI Address to file
65-
val uiTemp = fs.create(tmpUiPath, true)
66-
uiTemp.writeUTF(sc.ui.appUIAddress)
67-
uiTemp.close()
68-
fs.rename(tmpUiPath, uiPath)
6959
}
7060

7161
override def stop() {

core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/CoarseMesosSchedulerBackend.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ private[spark] class CoarseMesosSchedulerBackend(
181181
!slaveIdsWithExecutors.contains(slaveId)) {
182182
// Launch an executor on the slave
183183
val cpusToUse = math.min(cpus, maxCores - totalCoresAcquired)
184+
totalCoresAcquired += cpusToUse
184185
val taskId = newMesosTaskId()
185186
taskIdToSlaveId(taskId) = slaveId
186187
slaveIdsWithExecutors += slaveId

core/src/main/scala/org/apache/spark/storage/BlockManager.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,9 +889,9 @@ private[spark] object BlockManager extends Logging {
889889
blockManagerMaster: BlockManagerMaster = null)
890890
: Map[BlockId, Seq[BlockManagerId]] =
891891
{
892-
// env == null and blockManagerMaster != null is used in tests
892+
// blockManagerMaster != null is used in tests
893893
assert (env != null || blockManagerMaster != null)
894-
val blockLocations: Seq[Seq[BlockManagerId]] = if (env != null) {
894+
val blockLocations: Seq[Seq[BlockManagerId]] = if (blockManagerMaster == null) {
895895
env.blockManager.getLocationBlockIds(blockIds)
896896
} else {
897897
blockManagerMaster.getLocations(blockIds)

core/src/test/scala/org/apache/spark/scheduler/DAGSchedulerSuite.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class DAGSchedulerSuite extends FunSuite with BeforeAndAfter with LocalSparkCont
100100
cacheLocations.clear()
101101
results.clear()
102102
mapOutputTracker = new MapOutputTrackerMaster()
103-
scheduler = new DAGScheduler(taskScheduler, mapOutputTracker, blockManagerMaster, null) {
103+
scheduler = new DAGScheduler(taskScheduler, mapOutputTracker, blockManagerMaster, sc.env) {
104104
override def runLocally(job: ActiveJob) {
105105
// don't bother with the thread while unit testing
106106
runLocallyWithinThread(job)

docs/hadoop-third-party-distributions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ the _exact_ Hadoop version you are running to avoid any compatibility errors.
2525
<h3>CDH Releases</h3>
2626
<table class="table" style="width:350px; margin-right: 20px;">
2727
<tr><th>Release</th><th>Version code</th></tr>
28-
<tr><td>CDH 4.X.X (YARN mode)</td><td>2.0.0-chd4.X.X</td></tr>
29-
<tr><td>CDH 4.X.X</td><td>2.0.0-mr1-chd4.X.X</td></tr>
28+
<tr><td>CDH 4.X.X (YARN mode)</td><td>2.0.0-cdh4.X.X</td></tr>
29+
<tr><td>CDH 4.X.X</td><td>2.0.0-mr1-cdh4.X.X</td></tr>
3030
<tr><td>CDH 3u6</td><td>0.20.2-cdh3u6</td></tr>
3131
<tr><td>CDH 3u5</td><td>0.20.2-cdh3u5</td></tr>
3232
<tr><td>CDH 3u4</td><td>0.20.2-cdh3u4</td></tr>

project/SparkBuild.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ object SparkBuild extends Build {
328328
case m if m.toLowerCase.endsWith("manifest.mf") => MergeStrategy.discard
329329
case m if m.toLowerCase.matches("meta-inf.*\\.sf$") => MergeStrategy.discard
330330
case "log4j.properties" => MergeStrategy.discard
331-
case "META-INF/services/org.apache.hadoop.fs.FileSystem" => MergeStrategy.concat
331+
case m if m.toLowerCase.startsWith("meta-inf/services/") => MergeStrategy.filterDistinctLines
332332
case "reference.conf" => MergeStrategy.concat
333333
case _ => MergeStrategy.first
334334
}

0 commit comments

Comments
 (0)