Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,13 @@ private[spark] class AppStatusStore(
}
}

def stageAttempt(stageId: Int, stageAttemptId: Int, details: Boolean = false): v1.StageData = {
def stageAttempt(stageId: Int, stageAttemptId: Int,

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.

Changing the return type to (StageData, jobIds) might be simpler.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

details: Boolean = false): (v1.StageData, Seq[Int]) = {

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.

indent , you might make it look like taskSummary

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done, thanks!

val stageKey = Array(stageId, stageAttemptId)
val stage = store.read(classOf[StageDataWrapper], stageKey).info
if (details) stageWithDetails(stage) else stage
val stageDataWrapper: StageDataWrapper = store.read(classOf[StageDataWrapper], stageKey)

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.

you don't really need the type here (: StageDataWrapper)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done, thanks!

val stage = if (details) stageWithDetails(stageDataWrapper.info) else stageDataWrapper.info
val jobIds = stageDataWrapper.jobIds

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.

instead of having separate val just put this in the return:

(stage, stageDataWrapper.jobIds.toSeq)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

(stage, jobIds.toSeq)
}

def taskCount(stageId: Int, stageAttemptId: Int): Long = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private[v1] class StagesResource extends BaseAppResource {
@PathParam("stageAttemptId") stageAttemptId: Int,
@QueryParam("details") @DefaultValue("true") details: Boolean): StageData = withUI { ui =>
try {
ui.store.stageAttempt(stageId, stageAttemptId, details = details)
ui.store.stageAttempt(stageId, stageAttemptId, details = details)._1
} catch {
case _: NoSuchElementException =>
// Change the message depending on whether there are any attempts for the requested stage.
Expand Down
35 changes: 29 additions & 6 deletions core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
package org.apache.spark.ui.jobs

import java.net.URLEncoder
import java.util.Date
import java.util.{Date, NoSuchElementException}
import java.util.concurrent.TimeUnit
import javax.servlet.http.HttpServletRequest

Expand Down Expand Up @@ -105,15 +105,29 @@ private[ui] class StagePage(parent: StagesTab, store: AppStatusStore) extends We
val stageAttemptId = parameterAttempt.toInt

val stageHeader = s"Details for Stage $stageId (Attempt $stageAttemptId)"
val stageData = parent.store
.asOption(parent.store.stageAttempt(stageId, stageAttemptId, details = false))
.getOrElse {
var stageDataTuple: Tuple2[StageData, Seq[Int]] = null
try {

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.

I think you could use options here instead of try and null checks to make this cleaner

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done, thanks!

stageDataTuple = parent.store.stageAttempt(stageId, stageAttemptId, details = false)
} catch {
case e: NoSuchElementException => e.getMessage
}
var stageData: StageData = null
var stageJobIds: Seq[Int] = null
if (stageDataTuple == null) {
stageData = {

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.

this code branch is unreachable.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It is unreachable by the IDE but during runtime, the code does work, I have confirmed that.

val content =
<div id="no-info">
<p>No information to display for Stage {stageId} (Attempt {stageAttemptId})</p>
<p>No information to display for Stage
{stageId}
(Attempt
{stageAttemptId})</p>
</div>
return UIUtils.headerSparkPage(request, stageHeader, content, parent)
}
} else {
stageData = stageDataTuple._1
stageJobIds = stageDataTuple._2
}

val localitySummary = store.localitySummary(stageData.stageId, stageData.attemptId)

Expand Down Expand Up @@ -182,6 +196,15 @@ private[ui] class StagePage(parent: StagesTab, store: AppStatusStore) extends We
{Utils.bytesToString(stageData.diskBytesSpilled)}
</li>
}}
{if (!stageJobIds.isEmpty) {

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.

This could throw an NPE if stageDataTuple is None

scala> var x:Seq[Int] = null
x: Seq[Int] = null

scala> x.isEmpty
java.lang.NullPointerException

@pgandhi999 pgandhi999 Sep 28, 2018

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Since, we are returning from the code if it is None, it should never reach there as far as I can tell.

<li>
<strong>Associated Job Ids: </strong>
{stageJobIds.map(jobId => {val detailUrl = "%s/jobs/job/?id=%s".format(
UIUtils.prependBaseUri(request, parent.basePath), jobId)
<a href={s"${detailUrl}"}>{s"${jobId}"} &nbsp;&nbsp;</a>
})}
</li>
}}
</ul>
</div>

Expand Down Expand Up @@ -1047,7 +1070,7 @@ private[ui] object ApiHelper {
}

def lastStageNameAndDescription(store: AppStatusStore, job: JobData): (String, String) = {
val stage = store.asOption(store.stageAttempt(job.stageIds.max, 0))
val stage = store.asOption(store.stageAttempt(job.stageIds.max, 0)._1)
(stage.map(_.name).getOrElse(""), stage.flatMap(_.description).getOrElse(job.name))
}

Expand Down