public void abortTransaction(long transactionId, boolean abortPrepared, String reason,
                                 TxnCommitAttachment txnCommitAttachment,
                                 List<TabletCommitInfo> finishedTablets,
                                 List<TabletFailInfo> failedTablets)
            throws UserException {
        if (transactionId < 0) {
            LOG.info("transaction id is {}, less than 0, maybe this is an old type load job, ignore abort operation",
                    transactionId);
            return;
        }
        TransactionState transactionState = null;
        readLock();
        try {
            transactionState = idToRunningTransactionState.get(transactionId);
        } finally {
            readUnlock();
        }
        if (transactionState == null) {
            // If the transaction state does not exist, this task might have been aborted by
            // the txntimeoutchecker thread. We need to perform some additional work.
            processNotFoundTxn(transactionId, reason, txnCommitAttachment);
            throw new TransactionNotFoundException(transactionId);
        }

        // update transaction state extra if exists
        if (txnCommitAttachment != null) {
            transactionState.setTxnCommitAttachment(txnCommitAttachment);
        }

        // before state transform
        TxnStateChangeCallback callback = transactionState.beforeStateTransform(TransactionStatus.ABORTED);
        boolean txnOperated = false;

        transactionState.writeLock();
        try {
            writeLock();
            try {
                txnOperated = unprotectAbortTransaction(transactionId, abortPrepared, reason);
            } finally {
                writeUnlock();
                transactionState.afterStateTransform(TransactionStatus.ABORTED, txnOperated, callback, reason);
            }

            persistTxnStateInTxnLevelLock(transactionState);
        } finally {
            transactionState.writeUnlock();
        }

        if (!txnOperated || transactionState.getTransactionStatus() != TransactionStatus.ABORTED) {
            return;
        }

        LOG.info("transaction:[{}] successfully rollback", transactionState);

        Database db = GlobalStateMgr.getCurrentState().getDb(dbId);
        if (db == null) {
            return;
        }
        for (Long tableId : transactionState.getTableIdList()) {
            Table table = db.getTable(tableId);
            if (table == null) {
                continue;
            }
            TransactionStateListener listener = stateListenerFactory.create(this, table);
            if (listener != null) {
                listener.postAbort(transactionState, finishedTablets, failedTablets);
            }
        }
    }
@Test
    public void testAbortTransactionWithNotFoundException() throws UserException {
        DatabaseTransactionMgr masterDbTransMgr =
                masterTransMgr.getDatabaseTransactionMgr(GlobalStateMgrTestUtil.testDbId1);

        long txnId1 = lableToTxnId.get(GlobalStateMgrTestUtil.testTxnLable1);
        expectedEx.expect(UserException.class);
        expectedEx.expectMessage("transaction not found");
        masterDbTransMgr.abortTransaction(txnId1, "test abort transaction", null);
    }