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]) = {
val stageKey = Array(stageId, stageAttemptId)
val stage = store.read(classOf[StageDataWrapper], stageKey).info
if (details) stageWithDetails(stage) else stage
val stageDataWrapper = store.read(classOf[StageDataWrapper], stageKey)
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
46 changes: 35 additions & 11 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,30 @@ 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 {
val content =
<div id="no-info">
<p>No information to display for Stage {stageId} (Attempt {stageAttemptId})</p>
</div>
return UIUtils.headerSparkPage(request, stageHeader, content, parent)
}
var stageDataTuple: Option[Tuple2[StageData, Seq[Int]]] = try {

@tgravescs tgravescs Sep 18, 2018

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.

can't we just simplify this to be close to what is was before but return the tuple:

val (stageData, stageJodIds) = parent.store
      .asOption(parent.store.stageAttempt(stageId, stageAttemptId, details = false))
      .getOrElse {
        val content =
          <div id="no-info">
            <p>No information to display for Stage {stageId} (Attempt {stageAttemptId})</p>
          </div>
        return UIUtils.headerSparkPage(stageHeader, content, parent)
      }

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.

Makes sense, simplified the code and tested it. Looks good. Thank you.

Some(parent.store.stageAttempt(stageId, stageAttemptId, details = false))
} catch {
case e: NoSuchElementException => e.getMessage
None
}
var stageData: StageData = null
var stageJobIds: Seq[Int] = null
stageDataTuple match {
case Some(stageTuple) =>
stageData = stageTuple._1
stageJobIds = stageTuple._2
case None =>
stageData = {
val content =
<div id="no-info">
<p>No information to display for Stage
{stageId}
(Attempt
{stageAttemptId})</p>
</div>
return UIUtils.headerSparkPage(request, stageHeader, content, parent)
}
}

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

Expand Down Expand Up @@ -182,6 +197,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 +1071,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