Github user srowen commented on a diff in the pull request:
https://github.com/apache/spark/pull/22645#discussion_r223188205
--- Diff:
sql/core/src/main/scala/org/apache/spark/sql/execution/ui/AllExecutionsPage.scala
---
@@ -121,65 +122,247 @@ private[ui] class AllExecutionsPage(parent: SQLTab)
extends WebUIPage("") with L
{
if (running.nonEmpty) {
<li>
- <a href="#running-execution-table"><strong>Running
Queries:</strong></a>
+ <a href="#running"><strong>Running Queries:</strong></a>
{running.size}
</li>
}
}
{
if (completed.nonEmpty) {
<li>
- <a href="#completed-execution-table"><strong>Completed
Queries:</strong></a>
+ <a href="#completed"><strong>Completed
Queries:</strong></a>
{completed.size}
</li>
}
}
{
if (failed.nonEmpty) {
<li>
- <a href="#failed-execution-table"><strong>Failed
Queries:</strong></a>
+ <a href="#failed"><strong>Failed Queries:</strong></a>
{failed.size}
</li>
}
}
</ul>
</div>
+
UIUtils.headerSparkPage(request, "SQL", summary ++ content, parent,
Some(5000))
}
+
+ private def executionsTable(
+ request: HttpServletRequest,
+ executionTag: String,
+ executionData: Seq[SQLExecutionUIData],
+ currentTime: Long,
+ showRunningJobs: Boolean,
+ showSucceededJobs: Boolean,
+ showFailedJobs: Boolean): Seq[Node] = {
+
+ // stripXSS is called to remove suspicious characters used in XSS
attacks
+ val allParameters = request.getParameterMap.asScala.toMap.map { case
(k, v) =>
+ UIUtils.stripXSS(k) -> v.map(UIUtils.stripXSS).toSeq
+ }
+ val parameterOtherTable =
allParameters.filterNot(_._1.startsWith(executionTag))
+ .map(para => para._1 + "=" + para._2(0))
+
+ val parameterExecutionPage =
UIUtils.stripXSS(request.getParameter(executionTag + ".page"))
+ val parameterExecutionSortColumn = UIUtils.stripXSS(request.
+ getParameter(executionTag + ".sort"))
+ val parameterExecutionSortDesc =
UIUtils.stripXSS(request.getParameter(executionTag + ".desc"))
+ val parameterExecutionPageSize = UIUtils.stripXSS(request.
+ getParameter(executionTag + ".pageSize"))
+ val parameterExecutionPrevPageSize = UIUtils.stripXSS(request.
+ getParameter(executionTag + ".prevPageSize"))
+
+ val executionPage =
Option(parameterExecutionPage).map(_.toInt).getOrElse(1)
+ val executionSortColumn = Option(parameterExecutionSortColumn).map {
sortColumn =>
+ UIUtils.decodeURLParameter(sortColumn)
+ }.getOrElse("ID")
+ val executionSortDesc =
Option(parameterExecutionSortDesc).map(_.toBoolean).getOrElse(
+ // New executions should be shown above old executions by default.
+ executionSortColumn == "ID"
+ )
+ val executionPageSize =
Option(parameterExecutionPageSize).map(_.toInt).getOrElse(100)
+ val executionPrevPageSize =
Option(parameterExecutionPrevPageSize).map(_.toInt).
+ getOrElse(executionPageSize)
+
+ val page: Int = {
+ // If the user has changed to a larger page size, then go to page 1
in order to avoid
+ // IndexOutOfBoundsException.
+ if (executionPageSize <= executionPrevPageSize) {
+ executionPage
+ } else {
+ 1
+ }
+ }
+
+ val tableHeaderId = executionTag // "running", "completed" or "failed"
+
+ try {
+ new ExecutionPagedTable(
+ request,
+ parent,
+ executionData,
+ tableHeaderId,
+ executionTag,
+ UIUtils.prependBaseUri(request, parent.basePath),
+ "SQL", // subPath
+ parameterOtherTable,
+ currentTime,
+ pageSize = executionPageSize,
+ sortColumn = executionSortColumn,
+ desc = executionSortDesc,
+ showRunningJobs,
+ showSucceededJobs,
+ showFailedJobs).table(page)
+ } catch {
+ case e@(_: IllegalArgumentException | _: IndexOutOfBoundsException)
=>
+ <div class="alert alert-error">
+ <p>Error while rendering execution table:</p>
+ <pre>
+ {Utils.exceptionString(e)}
+ </pre>
+ </div>
+ }
+ }
}
-private[ui] abstract class ExecutionTable(
+
+private[ui] class ExecutionPagedTable(
+ request: HttpServletRequest,
parent: SQLTab,
- tableId: String,
+ data: Seq[SQLExecutionUIData],
+ tableHeaderId: String,
+ executionTag: String,
+ basePath: String,
+ subPath: String,
+ parameterOtherTable: Iterable[String],
currentTime: Long,
- executionUIDatas: Seq[SQLExecutionUIData],
+ pageSize: Int,
+ sortColumn: String,
+ desc: Boolean,
showRunningJobs: Boolean,
showSucceededJobs: Boolean,
- showFailedJobs: Boolean) {
+ showFailedJobs: Boolean) extends PagedTable[ExecutionTableRowData] {
- protected def baseHeader: Seq[String] = Seq(
- "ID",
- "Description",
- "Submitted",
- "Duration")
+ override val dataSource = new ExecutionDataSource(
+ request,
+ parent,
+ data,
+ basePath,
+ currentTime,
+ pageSize,
+ sortColumn,
+ desc)
- protected def header: Seq[String]
+ val parameterPath = basePath + s"/$subPath/?" +
parameterOtherTable.mkString("&")
- protected def row(
- request: HttpServletRequest,
- currentTime: Long,
- executionUIData: SQLExecutionUIData): Seq[Node] = {
- val submissionTime = executionUIData.submissionTime
- val duration =
executionUIData.completionTime.map(_.getTime()).getOrElse(currentTime) -
- submissionTime
+ override def tableId: String = executionTag + "-table"
- def jobLinks(status: JobExecutionStatus): Seq[Node] = {
- executionUIData.jobs.flatMap { case (jobId, jobStatus) =>
- if (jobStatus == status) {
- <a href={jobURL(request, jobId)}>[{jobId.toString}]</a>
+ override def tableCssClass: String =
+ "table table-bordered table-condensed table-striped " +
+ "table-head-clickable table-cell-width-limited"
+
+ override def prevPageSizeFormField: String = executionTag +
".prevPageSize"
+
+ override def pageLink(page: Int): String = {
+ val encodedSortColumn = URLEncoder.encode(sortColumn, "UTF-8")
+ parameterPath +
+ s"&$pageNumberFormField=$page" +
+ s"&$executionTag.sort=$encodedSortColumn" +
+ s"&$executionTag.desc=$desc" +
+ s"&$pageSizeFormField=$pageSize" +
+ s"#$tableHeaderId"
+ }
+
+ override def pageSizeFormField: String = executionTag + ".pageSize"
+
+ override def pageNumberFormField: String = executionTag + ".page"
+
+ override def goButtonFormPath: String = {
+ val encodedSortColumn = URLEncoder.encode(sortColumn, "UTF-8")
+
s"$parameterPath&$executionTag.sort=$encodedSortColumn&$executionTag.desc=$desc#$tableHeaderId"
+ }
+
+ override def headers: Seq[Node] = {
+ // Information for each header: title, cssClass, and sortable
+ val executionHeadersAndCssClasses: Seq[(String, String, Boolean)] =
+ Seq(("ID", "", true), ("Description", "", true), ("Submitted", "",
true),
+ ("Duration", "", true)) ++ {
+ if (showRunningJobs && showSucceededJobs && showFailedJobs) {
+ Seq(("Running Job IDs", "", true), ("Succeeded Job IDs", "",
true),
+ ("Failed Job IDs", "", true))
+ } else if (showSucceededJobs && showFailedJobs) {
+ Seq(("Succeeded Job IDs", "", true), ("Failed Job IDs", "",
true))
+ }
+ else {
+ Seq(("Job IDs", "", true))
+ }
+ }
+
+ if
(!executionHeadersAndCssClasses.filter(_._3).map(_._1).contains(sortColumn)) {
+ throw new IllegalArgumentException(s"Unknown column: $sortColumn")
+ }
+
+ val headerRow: Seq[Node] = {
+ executionHeadersAndCssClasses.map { case (header, cssClass,
sortable) =>
+ if (header == sortColumn) {
+ val headerLink = Unparsed(
+ parameterPath +
+ s"&$executionTag.sort=${URLEncoder.encode(header, "UTF-8")}"
+
+ s"&$executionTag.desc=${!desc}" +
+ s"&$executionTag.pageSize=$pageSize" +
+ s"#$tableHeaderId")
+ val arrow = if (desc) "▾" else "▴" // UP or DOWN
+
+ <th class={cssClass}>
+ <a href={headerLink}>
+ {header}<span>
+ {Unparsed(arrow)}
+ </span>
+ </a>
+ </th>
} else {
- None
+ if (sortable) {
+ val headerLink = Unparsed(
+ parameterPath +
+ s"&$executionTag.sort=${URLEncoder.encode(header,
"UTF-8")}" +
+ s"&$executionTag.pageSize=$pageSize" +
+ s"#$tableHeaderId")
+
+ <th class={cssClass}>
+ <a href={headerLink}>
+ {header}
+ </a>
+ </th>
+ } else {
+ <th class={cssClass}>
+ {header}
+ </th>
+ }
}
+ }
+ }
+ <thead>
+ {headerRow}
+ </thead>
+ }
+
+ override def row(executionTableRow: ExecutionTableRowData): Seq[Node] = {
+ val executionUIData = executionTableRow.executionUIData
+ val submissionTime = executionUIData.submissionTime
+ val duration = executionTableRow.duration
+
+ def jobLinks(status: JobExecutionStatus): Seq[Node] = {
+ executionUIData.jobs.flatMap {
+ case (jobId, jobStatus) =>
--- End diff --
Might be a little more idiomatic to say...
```
case (jobId, jobStatus) if jobStatus == status => ...
case _ => none
```
but why not just filter first instead of flatMap?
---
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]