Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions fe/fe-core/src/main/cup/sql_parser.cup
Original file line number Diff line number Diff line change
Expand Up @@ -4369,6 +4369,10 @@ show_param ::=
{:
RESULT = new ShowAnalyzeStmt(tbl, parser.where, true);
:}
| KW_AUTO KW_JOBS opt_table_name:tbl opt_wild_where
{:
RESULT = new ShowAutoAnalyzeJobsStmt(tbl, parser.where);
:}
| KW_ANALYZE KW_TASK KW_STATUS INTEGER_LITERAL:jobId
{:
RESULT = new ShowAnalyzeTaskStatus(jobId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.doris.analysis;

import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowResultSetMetaData;
import org.apache.doris.statistics.JobPriority;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;

/**
* ShowAutoAnalyzeJobsStmt is used to show pending auto analysis jobs.
* syntax:
* SHOW AUTO ANALYZE JOBS
* [TABLE]
* [
* WHERE
* [PRIORITY = ["HIGH"|"MID"|"LOW"]]
* ]
*/
public class ShowAutoAnalyzeJobsStmt extends ShowStmt {
private static final String PRIORITY = "priority";
private static final ImmutableList<String> TITLE_NAMES = new ImmutableList.Builder<String>()
.add("catalog_name")
.add("db_name")
.add("tbl_name")
.add("col_list")
.add("priority")
.build();

private final TableName tableName;
private final Expr whereClause;

public ShowAutoAnalyzeJobsStmt(TableName tableName, Expr whereClause) {
this.tableName = tableName;
this.whereClause = whereClause;
}

// extract from predicate
private String jobPriority;

public String getPriority() {
Preconditions.checkArgument(isAnalyzed(),
"The stateValue must be obtained after the parsing is complete");
return jobPriority;
}

public Expr getWhereClause() {
Preconditions.checkArgument(isAnalyzed(),
"The whereClause must be obtained after the parsing is complete");
return whereClause;
}

@Override
public void analyze(Analyzer analyzer) throws UserException {
if (!ConnectContext.get().getSessionVariable().enableStats) {
throw new UserException("Analyze function is forbidden, you should add `enable_stats=true`"
+ "in your FE conf file");
}
super.analyze(analyzer);
if (tableName != null) {
tableName.analyze(analyzer);
String catalogName = tableName.getCtl();
String dbName = tableName.getDb();
String tblName = tableName.getTbl();
checkShowAnalyzePriv(catalogName, dbName, tblName);
}

// analyze where clause if not null
if (whereClause != null) {
analyzeSubPredicate(whereClause);
}
}

@Override
public ShowResultSetMetaData getMetaData() {
ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder();
for (String title : TITLE_NAMES) {
builder.addColumn(new Column(title, ScalarType.createVarchar(128)));
}
return builder.build();
}

@Override
public RedirectStatus getRedirectStatus() {
return RedirectStatus.FORWARD_NO_SYNC;
}

private void checkShowAnalyzePriv(String catalogName, String dbName, String tblName) throws AnalysisException {
if (!Env.getCurrentEnv().getAccessManager()
.checkTblPriv(ConnectContext.get(), catalogName, dbName, tblName, PrivPredicate.SHOW)) {
ErrorReport.reportAnalysisException(
ErrorCode.ERR_TABLEACCESS_DENIED_ERROR,
"SHOW ANALYZE",
ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),
dbName + ": " + tblName);
}
}

private void analyzeSubPredicate(Expr subExpr) throws AnalysisException {
if (subExpr == null) {
return;
}

boolean valid = true;

CHECK: {
if (subExpr instanceof BinaryPredicate) {
BinaryPredicate binaryPredicate = (BinaryPredicate) subExpr;
if (binaryPredicate.getOp() != BinaryPredicate.Operator.EQ) {
valid = false;
break CHECK;
}
} else {
valid = false;
break CHECK;
}

// left child
if (!(subExpr.getChild(0) instanceof SlotRef)) {
valid = false;
break CHECK;
}
String leftKey = ((SlotRef) subExpr.getChild(0)).getColumnName();
if (!PRIORITY.equalsIgnoreCase(leftKey)) {
valid = false;
break CHECK;
}

// right child
if (!(subExpr.getChild(1) instanceof StringLiteral)) {
valid = false;
break CHECK;
}

String value = subExpr.getChild(1).getStringValue();
if (Strings.isNullOrEmpty(value)) {
valid = false;
break CHECK;
}

jobPriority = value.toUpperCase();
try {
JobPriority.valueOf(jobPriority);
} catch (Exception e) {
valid = false;
}
}

if (!valid) {
throw new AnalysisException("Where clause should looks like: "
+ "PRIORITY = \"HIGH|MID|LOW\"");
}
}

@Override
public String toSql() {
StringBuilder sb = new StringBuilder();
sb.append("SHOW AUTO ANALYZE");

if (tableName != null) {
sb.append(" ");
sb.append(tableName.toSql());
}

if (whereClause != null) {
sb.append(" ");
sb.append("WHERE");
sb.append(" ");
sb.append(whereClause.toSql());
}

return sb.toString();
}

@Override
public String toString() {
return toSql();
}

public TableName getTableName() {
return tableName;
}
}
34 changes: 34 additions & 0 deletions fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.doris.analysis.ShowAnalyzeStmt;
import org.apache.doris.analysis.ShowAnalyzeTaskStatus;
import org.apache.doris.analysis.ShowAuthorStmt;
import org.apache.doris.analysis.ShowAutoAnalyzeJobsStmt;
import org.apache.doris.analysis.ShowBackendsStmt;
import org.apache.doris.analysis.ShowBackupStmt;
import org.apache.doris.analysis.ShowBrokerStmt;
Expand Down Expand Up @@ -203,6 +204,7 @@
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.Privilege;
import org.apache.doris.statistics.AnalysisInfo;
import org.apache.doris.statistics.AutoAnalysisPendingJob;
import org.apache.doris.statistics.ColumnStatistic;
import org.apache.doris.statistics.Histogram;
import org.apache.doris.statistics.ResultRow;
Expand Down Expand Up @@ -440,6 +442,8 @@ public ShowResultSet execute() throws AnalysisException {
handleShowCreateCatalog();
} else if (stmt instanceof ShowAnalyzeStmt) {
handleShowAnalyze();
} else if (stmt instanceof ShowAutoAnalyzeJobsStmt) {
handleShowAutoAnalyzePendingJobs();
} else if (stmt instanceof ShowTabletsBelongStmt) {
handleShowTabletsBelong();
} else if (stmt instanceof AdminCopyTabletStmt) {
Expand Down Expand Up @@ -2865,6 +2869,36 @@ private void handleShowAnalyze() {
resultSet = new ShowResultSet(showStmt.getMetaData(), resultRows);
}

private void handleShowAutoAnalyzePendingJobs() {
ShowAutoAnalyzeJobsStmt showStmt = (ShowAutoAnalyzeJobsStmt) stmt;
List<AutoAnalysisPendingJob> jobs = Env.getCurrentEnv().getAnalysisManager().showAutoPendingJobs(showStmt);
List<List<String>> resultRows = Lists.newArrayList();
for (AutoAnalysisPendingJob job : jobs) {
try {
List<String> row = new ArrayList<>();
CatalogIf<? extends DatabaseIf<? extends TableIf>> c
= StatisticsUtil.findCatalog(job.catalogName);
row.add(c.getName());
Optional<? extends DatabaseIf<? extends TableIf>> databaseIf = c.getDb(job.dbName);
row.add(databaseIf.isPresent() ? databaseIf.get().getFullName() : "DB may get deleted");
if (databaseIf.isPresent()) {
Optional<? extends TableIf> table = databaseIf.get().getTable(job.tableName);
row.add(table.isPresent() ? table.get().getName() : "Table may get deleted");
} else {
row.add("DB may get deleted");
}
row.add(job.getColumnNames());
row.add(String.valueOf(job.priority));
resultRows.add(row);
} catch (Exception e) {
LOG.warn("Failed to get pending jobs for table {}.{}.{}, reason: {}",
job.catalogName, job.dbName, job.tableName, e.getMessage());
continue;
}
}
resultSet = new ShowResultSet(showStmt.getMetaData(), resultRows);
}

private void handleShowTabletsBelong() {
ShowTabletsBelongStmt showStmt = (ShowTabletsBelongStmt) stmt;
List<List<String>> rows = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.doris.analysis.DropStatsStmt;
import org.apache.doris.analysis.KillAnalysisJobStmt;
import org.apache.doris.analysis.ShowAnalyzeStmt;
import org.apache.doris.analysis.ShowAutoAnalyzeJobsStmt;
import org.apache.doris.analysis.TableName;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.DatabaseIf;
Expand Down Expand Up @@ -113,9 +114,9 @@ public class AnalysisManager implements Writable {
private static final int COLUMN_QUEUE_SIZE = 1000;
public final Queue<HighPriorityColumn> highPriorityColumns = new ArrayBlockingQueue<>(COLUMN_QUEUE_SIZE);
public final Queue<HighPriorityColumn> midPriorityColumns = new ArrayBlockingQueue<>(COLUMN_QUEUE_SIZE);
public final Map<TableIf, Set<String>> highPriorityJobs = new LinkedHashMap<>();
public final Map<TableIf, Set<String>> midPriorityJobs = new LinkedHashMap<>();
public final Map<TableIf, Set<String>> lowPriorityJobs = new LinkedHashMap<>();
public final Map<TableName, Set<String>> highPriorityJobs = new LinkedHashMap<>();
public final Map<TableName, Set<String>> midPriorityJobs = new LinkedHashMap<>();
public final Map<TableName, Set<String>> lowPriorityJobs = new LinkedHashMap<>();

// Tracking running manually submitted async tasks, keep in mem only
protected final ConcurrentMap<Long, Map<Long, BaseAnalysisTask>> analysisJobIdToTaskMap = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -595,6 +596,39 @@ public void updateTableStatsForAlterStats(AnalysisInfo jobInfo, TableIf tbl) {
}
}

public List<AutoAnalysisPendingJob> showAutoPendingJobs(ShowAutoAnalyzeJobsStmt stmt) {
TableName tblName = stmt.getTableName();
String priority = stmt.getPriority();
List<AutoAnalysisPendingJob> result = Lists.newArrayList();
if (priority == null || priority.isEmpty()) {
result.addAll(getPendingJobs(highPriorityJobs, JobPriority.HIGH, tblName));
result.addAll(getPendingJobs(midPriorityJobs, JobPriority.MID, tblName));
result.addAll(getPendingJobs(lowPriorityJobs, JobPriority.LOW, tblName));
} else if (priority.equals(JobPriority.HIGH.name())) {
result.addAll(getPendingJobs(highPriorityJobs, JobPriority.HIGH, tblName));
} else if (priority.equals(JobPriority.MID.name())) {
result.addAll(getPendingJobs(midPriorityJobs, JobPriority.MID, tblName));
} else if (priority.equals(JobPriority.LOW.name())) {
result.addAll(getPendingJobs(lowPriorityJobs, JobPriority.LOW, tblName));
}
return result;
}

protected List<AutoAnalysisPendingJob> getPendingJobs(Map<TableName, Set<String>> jobMap,
JobPriority priority, TableName tblName) {
List<AutoAnalysisPendingJob> result = Lists.newArrayList();
synchronized (jobMap) {
for (Entry<TableName, Set<String>> entry : jobMap.entrySet()) {
TableName table = entry.getKey();
if (tblName == null || tblName.equals(table)) {
result.add(new AutoAnalysisPendingJob(table.getCtl(),
table.getDb(), table.getTbl(), entry.getValue(), priority));
}
}
}
return result;
}

public List<AnalysisInfo> showAnalysisJob(ShowAnalyzeStmt stmt) {
return findShowAnalyzeResult(analysisJobInfoMap.values(), stmt);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.doris.statistics;

import java.util.Set;
import java.util.StringJoiner;

public class AutoAnalysisPendingJob {

public final String catalogName;
public final String dbName;
public final String tableName;
public final Set<String> columnNames;
public final JobPriority priority;

public AutoAnalysisPendingJob(String catalogName, String dbName, String tableName,
Set<String> columnNames, JobPriority priority) {
this.catalogName = catalogName;
this.dbName = dbName;
this.tableName = tableName;
this.columnNames = columnNames;
this.priority = priority;
}

public String getColumnNames() {
if (columnNames == null) {
return "";
}
StringJoiner stringJoiner = new StringJoiner(",");
for (String colName : columnNames) {
stringJoiner.add(colName);
}
return stringJoiner.toString();
}
}
Loading