morningman opened a new pull request, #69566:
URL: https://github.com/apache/doris/pull/69566

   ### What problem does this PR solve?
   
   Issue Number: None
   
   Related PR: #66473, #66530
   
   Problem Summary:
   
   **In short.** A prepared statement's `COM_STMT_EXECUTE` that fails after its 
scans were planned leaves its query-finish callbacks registered for good, keeps 
its connector scope open until the statement's next EXECUTE (or forever), and 
never stops the scan nodes left for the end of the statement. This PR ends 
every EXECUTE the way a COM_QUERY statement ends, which is what branch-4.x 
(#66473) does in `handleExecute`.
   
   **Background.** A plugin scan registers a query-finish callback while it 
plans its splits (`PluginDrivenScanNode.getSplits` → `QueryFinishCleanup`, 
keyed by the query id). The callback releases the connector's per-query read 
transaction (Hive full-ACID and insert-only reads open a metastore read 
transaction with a shared read lock during `planScan`) and closes the 
statement's connector scope, which holds connector metadata and any connector 
write transaction the executor has not finished. It runs when the query is 
unregistered: `StmtExecutor.finalizeQuery` → `QeProcessorImpl.unregisterQuery` 
→ `QueryFinishCallbackRegistry.runAndClear`. A COM_QUERY statement also closes 
its `StatementContext` in `ConnectProcessor`'s per-statement finally, which 
closes the scope of statements that never registered a callback and stops the 
scan nodes registered to stop at the statement end (a remote Doris scan sends 
its CloseSession there).
   
   **The problem, and what it cost.** `MysqlConnectProcessor.handleExecute` has 
neither. An execution that fails after planning never reaches `finalizeQuery`: 
a scan-level SQL block rule (`checkBlockRulesByScan` runs after `planner.plan` 
and before `handleQueryWithRetry`), or a prepared `INSERT ... SELECT` whose 
transaction fails to begin.
   
   | What the failed EXECUTE leaves behind | Master today | After this PR |
   |---|---|---|
   | Its `QueryFinishCleanup` in the process-wide registry | kept for good: the 
next EXECUTE has a new query id, and COM_STMT_CLOSE and a connection reset do 
not touch the registry | run and removed when the EXECUTE ends |
   | A connector read transaction / shared read lock opened while planning | 
not released by Doris | released when the EXECUTE ends |
   | Its connector scope (metadata, a connector write transaction never 
committed) | closed at the statement's next EXECUTE 
(`PreparedStatementContext.nextStatementContext`), never if there is none | 
closed when the EXECUTE ends |
   | Scan nodes registered to stop at the statement end | never stopped: 
`StatementContext.close()` never runs for an EXECUTE | stopped when the EXECUTE 
ends |
   
   **How this PR fixes it.** `handleExecute` runs the execution in a `try` 
whose `finally` unregisters the execution's query id and then closes the 
statement context that `ExecuteCommand` ran it with, which is the prepared 
statement's current context (`PreparedStatementContext.nextStatementContext`). 
Unregistering runs and drops the callbacks still registered for the query id, 
so they run in the same order as for a finished query: read-transaction release 
first, then the scope. Both calls are no-ops for an execution that finished 
normally: `finalizeQuery` already unregistered its query id (`runAndClear` 
finds nothing), and the scope's `closeAll` is close-once. The master-side 
forwarded path already closes the statement context after `handleExecute`, and 
closing it twice is a no-op. A binary-protocol execution has sent its whole 
result when `execute` returns (Arrow Flight does not use this path), so nothing 
still running is closed.
   
   **Results.** `MysqlConnectProcessorExecuteCleanupTest` (new) drives 
`handleExecute` with an executor that does what planning leaves behind:
   
   - an EXECUTE that registers a query-finish callback and is then rejected (a 
SQL block rule) runs that callback once and closes its scope;
   - an EXECUTE that fails before any scan registered closes its scope;
   - a successful EXECUTE, whose query is unregistered by `finalizeQuery`, runs 
its callback once and closes its scope value once.
   
   With `handleExecute` of master, the first two fail (`expected: <1> but was: 
<0>` for the callback and for the scope close) and the third passes. 
`MysqlConnectProcessorLongDataTest` and `MysqlConnectProcessorCursorFetchTest` 
mock the executor so that it never executes; their connections now carry the 
query id the statement's PREPARE left, as a real connection does. These 3 
classes and `ExecuteCommandTest`, `ConnectProcessorForwardProtocolTest`, 
`ConnectProcessorRetryTest`, `StatementContextTest`, 
`QueryFinishCallbackRegistryTest`, `PluginDrivenScanNodeReadTxnReleaseTest`, 
`AuditLogWorkloadGroupTest` and `TaskProcessorTest` pass (77 tests).
   
   ### Release note
   
   None
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [ ] Regression test
       - [x] Unit Test
       - [ ] Manual test (add detailed scripts or steps below)
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason <!-- Add your reason?  -->
   
   - Behavior changed:
       - [x] No.
       - [ ] Yes. <!-- Explain the behavior change -->
   
   - Does this need documentation?
       - [x] No.
       - [ ] Yes. <!-- Add document PR link here. eg: 
https://github.com/apache/doris-website/pull/1214 -->
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label <!-- Add branch pick label that this PR should 
merge into -->
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to