From 6ef819d49d2fa3212067962cfd6afb4782df63c2 Mon Sep 17 00:00:00 2001 From: kkop <2449402815@qq.com> Date: Mon, 14 Oct 2024 22:17:34 +0800 Subject: [PATCH] [enhance](branch-3.0)support show-transaction (#41797) --- .../CloudGlobalTransactionMgr.java | 19 ++++- .../transaction/DatabaseTransactionMgr.java | 61 ++------------- .../doris/transaction/TransactionUtil.java | 77 +++++++++++++++++++ .../conf/regression-conf-custom.groovy | 1 - .../show/test_show_transaction.groovy | 7 +- 5 files changed, 104 insertions(+), 61 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/transaction/TransactionUtil.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/cloud/transaction/CloudGlobalTransactionMgr.java b/fe/fe-core/src/main/java/org/apache/doris/cloud/transaction/CloudGlobalTransactionMgr.java index 78f39de39577ae..748642272cfa11 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/cloud/transaction/CloudGlobalTransactionMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/cloud/transaction/CloudGlobalTransactionMgr.java @@ -112,6 +112,7 @@ import org.apache.doris.transaction.TransactionState.LoadJobSourceType; import org.apache.doris.transaction.TransactionState.TxnCoordinator; import org.apache.doris.transaction.TransactionStatus; +import org.apache.doris.transaction.TransactionUtil; import org.apache.doris.transaction.TxnCommitAttachment; import org.apache.doris.transaction.TxnStateCallbackFactory; import org.apache.doris.transaction.TxnStateChangeCallback; @@ -1507,7 +1508,14 @@ public TransactionStatus getLabelState(long dbId, String label) throws AnalysisE @Override public Long getTransactionId(Long dbId, String label) throws AnalysisException { - throw new AnalysisException(NOT_SUPPORTED_MSG); + try { + TransactionStatus labelState = getLabelState(dbId, label); + List statusList = Lists.newArrayList(labelState); + return getTransactionIdByLabel(dbId, label, statusList); + } catch (UserException e) { + LOG.warn("Get transaction id by label " + label + " failed", e); + return null; + } } @Override @@ -1688,7 +1696,14 @@ public List> getDbTransInfoByLabelMatch(long dbId, String label) th @Override public List> getSingleTranInfo(long dbId, long txnId) throws AnalysisException { - throw new AnalysisException(NOT_SUPPORTED_MSG); + List> infos = new ArrayList>(); + TransactionState txnState = this.getTransactionState(dbId, txnId); + if (txnState == null) { + throw new AnalysisException("transaction with id " + txnId + " does not exist"); + } + TransactionUtil.checkAuth(dbId, txnState); + infos.add(TransactionUtil.getTxnStateInfo(txnState, Lists.newArrayList())); + return infos; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java b/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java index a236bea0625678..39ecbfd30a8068 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java @@ -36,8 +36,6 @@ import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; import org.apache.doris.common.DuplicatedRequestException; -import org.apache.doris.common.ErrorCode; -import org.apache.doris.common.ErrorReport; import org.apache.doris.common.FeNameFormat; import org.apache.doris.common.LabelAlreadyUsedException; import org.apache.doris.common.LoadException; @@ -50,12 +48,9 @@ import org.apache.doris.common.util.DebugUtil; import org.apache.doris.common.util.InternalDatabaseUtil; import org.apache.doris.common.util.MetaLockUtils; -import org.apache.doris.common.util.TimeUtils; -import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.event.DataChangeEvent; import org.apache.doris.metric.MetricRepo; import org.apache.doris.mtmv.MTMVUtil; -import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.persist.BatchRemoveTransactionsOperationV2; import org.apache.doris.persist.CleanLabelOperationLog; import org.apache.doris.persist.EditLog; @@ -249,9 +244,7 @@ public List> getTxnStateInfoList(boolean running, int limit) { .sorted(TransactionState.TXN_ID_COMPARATOR) .limit(limit) .forEach(t -> { - List info = Lists.newArrayList(); - getTxnStateInfo(t, info); - infos.add(info); + infos.add(TransactionUtil.getTxnStateInfo(t, Lists.newArrayList())); }); } finally { readUnlock(); @@ -287,9 +280,7 @@ public List> getTxnStateInfoList(TransactionStatus status) { .filter(transactionState -> (transactionState.getTransactionStatus() == status)) .sorted(TransactionState.TXN_ID_COMPARATOR) .forEach(t -> { - List info = Lists.newArrayList(); - getTxnStateInfo(t, info); - infos.add(info); + infos.add(TransactionUtil.getTxnStateInfo(t, Lists.newArrayList())); }); } finally { readUnlock(); @@ -309,9 +300,7 @@ public List> getTxnStateInfoList(String labelRegex) { .filter(transactionState -> (transactionState.getLabel().matches(labelRegex))) .sorted(TransactionState.TXN_ID_COMPARATOR) .forEach(t -> { - List info = Lists.newArrayList(); - getTxnStateInfo(t, info); - infos.add(info); + infos.add(TransactionUtil.getTxnStateInfo(t, Lists.newArrayList())); }); } finally { readUnlock(); @@ -319,23 +308,6 @@ public List> getTxnStateInfoList(String labelRegex) { return infos; } - private void getTxnStateInfo(TransactionState txnState, List info) { - info.add(String.valueOf(txnState.getTransactionId())); - info.add(txnState.getLabel()); - info.add(txnState.getCoordinator().toString()); - info.add(txnState.getTransactionStatus().name()); - info.add(txnState.getSourceType().name()); - info.add(TimeUtils.longToTimeString(txnState.getPrepareTime())); - info.add(TimeUtils.longToTimeString(txnState.getPreCommitTime())); - info.add(TimeUtils.longToTimeString(txnState.getCommitTime())); - info.add(TimeUtils.longToTimeString(txnState.getLastPublishVersionTime())); - info.add(TimeUtils.longToTimeString(txnState.getFinishTime())); - info.add(txnState.getReason()); - info.add(String.valueOf(txnState.getErrorReplicas().size())); - info.add(String.valueOf(txnState.getCallbackId())); - info.add(String.valueOf(txnState.getTimeoutMs())); - info.add(txnState.getErrMsg()); - } public long beginTransaction(List tableIdList, String label, TUniqueId requestId, TransactionState.TxnCoordinator coordinator, TransactionState.LoadJobSourceType sourceType, @@ -2069,35 +2041,12 @@ public List> getSingleTranInfo(long dbId, long txnId) throws Analys List> infos = new ArrayList>(); readLock(); try { - Database db = Env.getCurrentInternalCatalog().getDbOrAnalysisException(dbId); TransactionState txnState = unprotectedGetTransactionState(txnId); if (txnState == null) { throw new AnalysisException("transaction with id " + txnId + " does not exist"); } - - if (ConnectContext.get() != null) { - // check auth - Set tblIds = txnState.getIdToTableCommitInfos().keySet(); - for (Long tblId : tblIds) { - Table tbl = db.getTableNullable(tblId); - if (tbl != null) { - if (!Env.getCurrentEnv().getAccessManager() - .checkTblPriv(ConnectContext.get(), InternalCatalog.INTERNAL_CATALOG_NAME, - db.getFullName(), - tbl.getName(), PrivPredicate.SHOW)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, - "SHOW TRANSACTION", - ConnectContext.get().getQualifiedUser(), - ConnectContext.get().getRemoteIP(), - db.getFullName() + ": " + tbl.getName()); - } - } - } - } - - List info = Lists.newArrayList(); - getTxnStateInfo(txnState, info); - infos.add(info); + TransactionUtil.checkAuth(dbId, txnState); + infos.add(TransactionUtil.getTxnStateInfo(txnState, Lists.newArrayList())); } finally { readUnlock(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/transaction/TransactionUtil.java b/fe/fe-core/src/main/java/org/apache/doris/transaction/TransactionUtil.java new file mode 100644 index 00000000000000..0a5fa0de5c8571 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/transaction/TransactionUtil.java @@ -0,0 +1,77 @@ +// 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.transaction; + +import org.apache.doris.catalog.Database; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.Table; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.util.TimeUtils; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; + +import java.util.List; +import java.util.Set; + +public class TransactionUtil { + + public static List getTxnStateInfo(TransactionState txnState, List info) { + info.add(String.valueOf(txnState.getTransactionId())); + info.add(txnState.getLabel()); + info.add(txnState.getCoordinator().toString()); + info.add(txnState.getTransactionStatus().name()); + info.add(txnState.getSourceType().name()); + info.add(TimeUtils.longToTimeString(txnState.getPrepareTime())); + info.add(TimeUtils.longToTimeString(txnState.getPreCommitTime())); + info.add(TimeUtils.longToTimeString(txnState.getCommitTime())); + info.add(TimeUtils.longToTimeString(txnState.getLastPublishVersionTime())); + info.add(TimeUtils.longToTimeString(txnState.getFinishTime())); + info.add(txnState.getReason()); + info.add(String.valueOf(txnState.getErrorReplicas().size())); + info.add(String.valueOf(txnState.getCallbackId())); + info.add(String.valueOf(txnState.getTimeoutMs())); + info.add(txnState.getErrMsg()); + return info; + } + + public static void checkAuth(long dbId, TransactionState txnState) throws AnalysisException { + Database db = Env.getCurrentInternalCatalog().getDbOrAnalysisException(dbId); + if (ConnectContext.get() != null) { + // check auth + Set tblIds = txnState.getIdToTableCommitInfos().keySet(); + for (Long tblId : tblIds) { + Table tbl = db.getTableNullable(tblId); + if (tbl != null) { + if (!Env.getCurrentEnv().getAccessManager() + .checkTblPriv(ConnectContext.get(), InternalCatalog.INTERNAL_CATALOG_NAME, + db.getFullName(), + tbl.getName(), PrivPredicate.SHOW)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, + "SHOW TRANSACTION", + ConnectContext.get().getQualifiedUser(), + ConnectContext.get().getRemoteIP(), + db.getFullName() + ": " + tbl.getName()); + } + } + } + } + } +} diff --git a/regression-test/pipeline/cloud_p0/conf/regression-conf-custom.groovy b/regression-test/pipeline/cloud_p0/conf/regression-conf-custom.groovy index 8d6b265a54bf02..2d9c6ad6978ab5 100644 --- a/regression-test/pipeline/cloud_p0/conf/regression-conf-custom.groovy +++ b/regression-test/pipeline/cloud_p0/conf/regression-conf-custom.groovy @@ -37,7 +37,6 @@ excludeSuites = "000_the_start_sentinel_do_not_touch," + // keep this line as th "test_refresh_mtmv," + // not supported yet "test_report_version_missing," + "test_set_partition_version," + - "test_show_transaction," + // not supported yet "test_spark_load," + "test_index_lowercase_fault_injection," + "test_index_compaction_failure_injection," + diff --git a/regression-test/suites/query_p0/show/test_show_transaction.groovy b/regression-test/suites/query_p0/show/test_show_transaction.groovy index fa7f0ddbdc97a2..79540d475b4439 100644 --- a/regression-test/suites/query_p0/show/test_show_transaction.groovy +++ b/regression-test/suites/query_p0/show/test_show_transaction.groovy @@ -36,7 +36,10 @@ suite("test_show_transaction", "p0") { def uuid = UUID.randomUUID().toString().replaceAll("-", ""); sql """ INSERT INTO ${testTable} WITH LABEL label_test_show_transaction_${uuid} VALUES(100, 'doris') """ def res = sql_return_maparray """ show transaction where label = 'label_test_show_transaction_${uuid}' """ + assertTrue(res.size() != 0) print("show transaction result : " + res) - def reslike = sql_return_maparray """ show transaction where label like 'label_test_show_transaction_${uuid}%' """ - assertTrue(res.equals(reslike)) + if (!isCloudMode()) { + def reslike = sql_return_maparray """ show transaction where label like 'label_test_show_transaction_${uuid}%' """ + assertTrue(res.equals(reslike)) + } }