-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-30359][CORE] Don't clear executorsPendingToRemove at the beginning of CoarseGrainedSchedulerBackend.reset #27017
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
511058c
3cfd80f
3368a3e
eae69ce
d12dd45
77c09e8
4fdb7cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,18 +21,22 @@ import java.util.{Properties, Random} | |
|
|
||
| import scala.collection.mutable | ||
| import scala.collection.mutable.ArrayBuffer | ||
| import scala.concurrent.duration._ | ||
|
|
||
| import org.apache.hadoop.fs.FileAlreadyExistsException | ||
| import org.mockito.ArgumentMatchers.{any, anyBoolean, anyInt, anyString} | ||
| import org.mockito.Mockito._ | ||
| import org.mockito.invocation.InvocationOnMock | ||
| import org.scalatest.Assertions._ | ||
| import org.scalatest.PrivateMethodTester | ||
| import org.scalatest.concurrent.Eventually | ||
|
|
||
| import org.apache.spark._ | ||
| import org.apache.spark.internal.Logging | ||
| import org.apache.spark.internal.config | ||
| import org.apache.spark.resource.ResourceUtils._ | ||
| import org.apache.spark.resource.TestResourceIDs._ | ||
| import org.apache.spark.scheduler.cluster.CoarseGrainedSchedulerBackend | ||
| import org.apache.spark.serializer.SerializerInstance | ||
| import org.apache.spark.storage.BlockManagerId | ||
| import org.apache.spark.util.{AccumulatorV2, ManualClock} | ||
|
|
@@ -179,7 +183,12 @@ class LargeTask(stageId: Int) extends Task[Array[Byte]](stageId, 0, 0) { | |
| override def preferredLocations: Seq[TaskLocation] = Seq[TaskLocation]() | ||
| } | ||
|
|
||
| class TaskSetManagerSuite extends SparkFunSuite with LocalSparkContext with Logging { | ||
| class TaskSetManagerSuite | ||
| extends SparkFunSuite | ||
| with LocalSparkContext | ||
| with PrivateMethodTester | ||
| with Eventually | ||
| with Logging { | ||
| import TaskLocality.{ANY, PROCESS_LOCAL, NO_PREF, NODE_LOCAL, RACK_LOCAL} | ||
|
|
||
| private val conf = new SparkConf | ||
|
|
@@ -1894,4 +1903,59 @@ class TaskSetManagerSuite extends SparkFunSuite with LocalSparkContext with Logg | |
| manager.handleFailedTask(offerResult.get.taskId, TaskState.FAILED, reason) | ||
| assert(sched.taskSetsFailed.contains(taskSet.id)) | ||
| } | ||
|
|
||
| test("SPARK-30359: don't clean executorsPendingToRemove at the beginning of 'reset'") { | ||
| val conf = new SparkConf() | ||
| // use local-cluster mode in order to get CoarseGrainedSchedulerBackend | ||
| .setMaster("local-cluster[2, 1, 2048]") | ||
| // allow to set up at most two executors | ||
| .set("spark.cores.max", "2") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we still need this config?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to create at most 2 executors at the beginning...Though, this may not necessary.. |
||
| .setAppName("CoarseGrainedSchedulerBackend.reset") | ||
| sc = new SparkContext(conf) | ||
| val sched = sc.taskScheduler | ||
| val backend = sc.schedulerBackend.asInstanceOf[CoarseGrainedSchedulerBackend] | ||
|
|
||
| TestUtils.waitUntilExecutorsUp(sc, 2, 60000) | ||
| val Seq(exec0, exec1) = backend.getExecutorIds() | ||
|
|
||
| val taskSet = FakeTask.createTaskSet(2) | ||
| val stageId = taskSet.stageId | ||
| val stageAttemptId = taskSet.stageAttemptId | ||
| sched.submitTasks(taskSet) | ||
| val taskSetManagers = PrivateMethod[mutable.HashMap[Int, mutable.HashMap[Int, TaskSetManager]]]( | ||
| Symbol("taskSetsByStageIdAndAttempt")) | ||
| // get the TaskSetManager | ||
| val manager = sched.invokePrivate(taskSetManagers()).get(stageId).get(stageAttemptId) | ||
|
|
||
| val task0 = manager.resourceOffer(exec0, "localhost", TaskLocality.NO_PREF) | ||
| val task1 = manager.resourceOffer(exec1, "localhost", TaskLocality.NO_PREF) | ||
| assert(task0.isDefined && task1.isDefined) | ||
| val (taskId0, index0) = (task0.get.taskId, task0.get.index) | ||
| val (taskId1, index1) = (task1.get.taskId, task1.get.index) | ||
| // set up two running tasks | ||
| assert(manager.taskInfos(taskId0).running) | ||
| assert(manager.taskInfos(taskId0).executorId === exec0) | ||
| assert(manager.taskInfos(taskId1).running) | ||
| assert(manager.taskInfos(taskId1).executorId === exec1) | ||
|
|
||
| val numFailures = PrivateMethod[Array[Int]](Symbol("numFailures")) | ||
| // no task failures yet | ||
| assert(manager.invokePrivate(numFailures())(index0) === 0) | ||
| assert(manager.invokePrivate(numFailures())(index1) === 0) | ||
|
|
||
| // task0 on exec0 should not count failures | ||
| backend.executorsPendingToRemove(exec0) = true | ||
| // task1 on exec1 should count failures | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what makes exec1 different from exec0 and count failures?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, |
||
| backend.executorsPendingToRemove(exec1) = false | ||
|
|
||
| backend.reset() | ||
|
|
||
| eventually(timeout(10.seconds), interval(100.milliseconds)) { | ||
| // executorsPendingToRemove should still be empty after reset() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: |
||
| assert(backend.executorsPendingToRemove.isEmpty) | ||
| assert(manager.invokePrivate(numFailures())(index0) === 0) | ||
| assert(manager.invokePrivate(numFailures())(index1) === 1) | ||
| } | ||
| sc.stop() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not necessary coz |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you still need to mention
CoarseGrainedSchedulerBackend.reset