@@ -336,30 +336,49 @@ private[spark] class TaskSetManager(
336
336
* Dequeue a pending task for a given node and return its index and locality level.
337
337
* Only search for tasks matching the given locality constraint.
338
338
*
339
+ * NOTE: minLocality is for avoiding duplicate traverse of the list (especially when we
340
+ * pass NOPREF as maxLocality after the others
341
+ *
339
342
* @return An option containing (task index within the task set, locality, is speculative?)
340
343
*/
341
- private def findTask (execId : String , host : String , locality : TaskLocality .Value )
342
- : Option [(Int , TaskLocality .Value , Boolean )] =
344
+ private def findTask (execId : String , host : String , maxLocality : TaskLocality .Value ,
345
+ minLocality : TaskLocality .Value )
346
+ : Option [(Int , TaskLocality .Value , Boolean )] =
343
347
{
344
- for (index <- findTaskFromList(execId, getPendingTasksForExecutor(execId))) {
345
- return Some ((index, TaskLocality .PROCESS_LOCAL , false ))
348
+ def withinAllowedLocality (locality : TaskLocality .TaskLocality ): Boolean = {
349
+ TaskLocality .isAllowed(maxLocality, locality) && {
350
+ if (maxLocality != minLocality) {
351
+ minLocality < locality
352
+ } else {
353
+ true
354
+ }
355
+ }
356
+ }
357
+
358
+ if (withinAllowedLocality(TaskLocality .PROCESS_LOCAL )) {
359
+ for (index <- findTaskFromList(execId, getPendingTasksForExecutor(execId))) {
360
+ return Some ((index, TaskLocality .PROCESS_LOCAL , false ))
361
+ }
346
362
}
347
363
348
- if (TaskLocality .isAllowed(locality, TaskLocality .NODE_LOCAL )) {
364
+ if (withinAllowedLocality( TaskLocality .NODE_LOCAL )) {
349
365
for (index <- findTaskFromList(execId, getPendingTasksForHost(host))) {
350
366
return Some ((index, TaskLocality .NODE_LOCAL , false ))
351
367
}
368
+ }
369
+
370
+ if (withinAllowedLocality(TaskLocality .NOPREF )) {
352
371
// Look for noPref tasks after NODE_LOCAL for minimize cross-rack traffic
353
372
for (index <- findTaskFromList(execId, pendingTasksWithNoPrefs)) {
354
373
return Some ((index, TaskLocality .PROCESS_LOCAL , false ))
355
374
}
356
375
// find a speculative task if all noPref tasks have been scheduled
357
- val specTask = findSpeculativeTask(execId, host, locality ).map {
376
+ val specTask = findSpeculativeTask(execId, host, maxLocality ).map {
358
377
case (taskIndex, allowedLocality) => (taskIndex, allowedLocality, true )}
359
378
if (specTask != None ) return specTask
360
379
}
361
380
362
- if (TaskLocality .isAllowed(locality, TaskLocality .RACK_LOCAL )) {
381
+ if (withinAllowedLocality( TaskLocality .RACK_LOCAL )) {
363
382
for {
364
383
rack <- sched.getRackForHost(host)
365
384
index <- findTaskFromList(execId, getPendingTasksForRack(rack))
@@ -368,31 +387,53 @@ private[spark] class TaskSetManager(
368
387
}
369
388
}
370
389
371
- if (TaskLocality .isAllowed(locality, TaskLocality .ANY )) {
390
+ if (withinAllowedLocality( TaskLocality .ANY )) {
372
391
for (index <- findTaskFromList(execId, allPendingTasks)) {
373
392
return Some ((index, TaskLocality .ANY , false ))
374
393
}
375
394
}
395
+
376
396
None
377
397
}
378
398
379
399
/**
380
400
* Respond to an offer of a single executor from the scheduler by finding a task
401
+ * @param execId the executor Id of the offered resource
402
+ * @param host the host Id of the offered resource
403
+ * @param preferredLocality the maximum locality we want to schedule the tasks at
404
+ * @param bottomLocality the minimum locality we want to schedule the tasks at, this
405
+ * parameter is mainly used to avoid some duplicate traversing of
406
+ * the task lists, after we have determined that we have no candidate
407
+ * tasks on certain levels
408
+ * @param allowAdjustPrefLocality this parameter is mainly for scheduling noPref tasks, where
409
+ * we do not want to apply delay scheduling on this kind of tasks
381
410
*/
382
411
def resourceOffer (
383
412
execId : String ,
384
413
host : String ,
385
- preferredLocality : TaskLocality .TaskLocality )
414
+ preferredLocality : TaskLocality .TaskLocality ,
415
+ bottomLocality : TaskLocality .TaskLocality ,
416
+ allowAdjustPrefLocality : Boolean = true )
386
417
: Option [TaskDescription ] =
387
418
{
388
419
if (! isZombie) {
389
420
val curTime = clock.getTime()
390
421
391
422
var allowedLocality = getAllowedLocalityLevel(curTime)
423
+
392
424
if (allowedLocality > preferredLocality) {
393
- allowedLocality = preferredLocality // We're not allowed to search for farther-away tasks
425
+ // We're not allowed to search for farther-away tasks
426
+ allowedLocality = preferredLocality
394
427
}
395
- findTask(execId, host, allowedLocality) match {
428
+
429
+ val foundTask = {
430
+ if (allowAdjustPrefLocality) {
431
+ findTask(execId, host, allowedLocality, bottomLocality)
432
+ } else {
433
+ findTask(execId, host, preferredLocality, bottomLocality)
434
+ }
435
+ }
436
+ foundTask match {
396
437
case Some ((index, taskLocality, speculative)) => {
397
438
// Found a task; do some bookkeeping and return a task description
398
439
val task = tasks(index)
@@ -433,6 +474,10 @@ private[spark] class TaskSetManager(
433
474
return Some (new TaskDescription (taskId, execId, taskName, index, serializedTask))
434
475
}
435
476
case _ =>
477
+ if (preferredLocality != TaskLocality .NOPREF ) {
478
+ return resourceOffer(execId, host, TaskLocality .NOPREF , preferredLocality,
479
+ allowAdjustPrefLocality = false )
480
+ }
436
481
}
437
482
}
438
483
None
@@ -634,8 +679,7 @@ private[spark] class TaskSetManager(
634
679
override def executorLost (execId : String , host : String ) {
635
680
logInfo(" Re-queueing tasks for " + execId + " from TaskSet " + taskSet.id)
636
681
637
- // Re-enqueue pending tasks for this host based on the status of the cluster -- for example, a
638
- // task that used to have locations on only this host might now go to the no-prefs list. Note
682
+ // Re-enqueue pending tasks for this host based on the status of the cluster. Note
639
683
// that it's okay if we add a task to the same queue twice (if it had multiple preferred
640
684
// locations), because findTaskFromList will skip already-running tasks.
641
685
for (index <- getPendingTasksForExecutor(execId)) {
@@ -666,6 +710,9 @@ private[spark] class TaskSetManager(
666
710
for ((tid, info) <- taskInfos if info.running && info.executorId == execId) {
667
711
handleFailedTask(tid, TaskState .FAILED , ExecutorLostFailure )
668
712
}
713
+ // recalculate valid locality levels and waits when executor is lost
714
+ myLocalityLevels = computeValidLocalityLevels()
715
+ localityWaits = myLocalityLevels.map(getLocalityWait)
669
716
}
670
717
671
718
/**
@@ -725,6 +772,8 @@ private[spark] class TaskSetManager(
725
772
/**
726
773
* Compute the locality levels used in this TaskSet. Assumes that all tasks have already been
727
774
* added to queues using addPendingTask.
775
+ *
776
+ * NOTE: don't need to handle NOPREF here, because NOPREF is scheduled as PROCESS_LOCAL
728
777
*/
729
778
private def computeValidLocalityLevels (): Array [TaskLocality .TaskLocality ] = {
730
779
import TaskLocality .{PROCESS_LOCAL , NODE_LOCAL , RACK_LOCAL , ANY }
@@ -747,16 +796,6 @@ private[spark] class TaskSetManager(
747
796
}
748
797
749
798
def executorAdded () {
750
- def newLocAvail (index : Int ): Boolean = {
751
- for (loc <- tasks(index).preferredLocations) {
752
- if (sched.hasExecutorsAliveOnHost(loc.host) ||
753
- (sched.getRackForHost(loc.host).isDefined &&
754
- sched.hasHostAliveOnRack(sched.getRackForHost(loc.host).get))) {
755
- return true
756
- }
757
- }
758
- false
759
- }
760
799
myLocalityLevels = computeValidLocalityLevels()
761
800
localityWaits = myLocalityLevels.map(getLocalityWait)
762
801
}
0 commit comments