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

   ### What problem does this PR solve?
   
   Issue Number: None
   
   Related PR: #67820, #69831
   
   Problem Summary:
   
   **In short:** in cloud mode, when MetaService answers a commit with 
`KV_TXN_COMMIT_ERR`, the FE gives up the commit TSO at once, as for a commit 
that failed for good. MetaService gives that answer when the FDB commit of the 
transaction timed out, and such a commit may still be applied afterwards. The 
committed TSO watermark can then pass a commit that is yet to land, and a 
bounded `@incr` read admitted at that watermark misses its rows. This PR 
advances the MetaService TSO fence to the TSO before giving it up on this 
answer, as the FE already does when the commit RPC itself fails.
   
   #### Background
   
   - In cloud mode the Master FE gives each commit a TSO and registers it 
before sending `commit_txn` to MetaService (#67820). The committed TSO 
watermark stays below the oldest registered TSO, and a bounded `@incr` read 
whose window ends at or below the watermark is admitted without waiting 
(`TSOService.waitForReadableWindow`), on the guarantee that no commit with a 
TSO at or below it can still land.
   - So a TSO is given up only once the outcome of its commit is settled. An 
answer of success, already visible or already aborted finishes the transaction. 
A failed RPC (a timeout, a lost connection) leaves the outcome open, so the FE 
first advances the MetaService TSO fence to the TSO 
(`TSOService.fenceAndAbandonCommitTso`): `commit_txn` reads the fence in the 
FDB transaction it commits and rejects a TSO at or below it, so once the fence 
is advanced, the commit has landed or can no longer land. Every other answer 
gives the TSO up at once.
   - MetaService gives each FDB transaction a timeout (`fdb_txn_timeout_ms`, 10 
seconds by default) and turns the error of an FDB commit into its answer 
through `cast_as<ErrCategory::COMMIT>`: a conflict is `KV_TXN_CONFLICT`, 
`commit_unknown_result` is `KV_TXN_MAYBE_COMMITTED`, and a timeout (FDB errors 
1004 `timed_out` and 1031 `transaction_timed_out`) or an error it does not 
classify is `KV_TXN_COMMIT_ERR`.
   
   #### The problem, and what it cost
   
   - A timeout cancels the FDB transaction, and the FoundationDB C API 
documents that for a transaction cancelled after its commit was sent, "the 
commit may have occurred or may occur in the future". So `KV_TXN_COMMIT_ERR` 
does not settle the outcome of the commit.
   - `CloudGlobalTransactionMgr.commitTxn` gives the TSO up on that answer 
without a fence. Once nothing older is registered, the watermark passes the TSO 
while the commit can still land.
   - A bounded `@incr` read admitted at that watermark misses the rows of a 
commit that lands later, and a read of the next window does not see them 
either: their TSO lies in the window already read. Anything else that takes the 
watermark as proof that no commit at or below it is coming is exposed the same 
way; the keep-alive of IVM streams in #69831 fences MetaService itself before 
it reads, for this reason.
   
   #### How this PR fixes it
   
   - `KV_TXN_COMMIT_ERR` takes the path of a failed RPC: 
`fenceAndAbandonCommitTso` advances the fence to the TSO and gives the TSO up 
only after that.
   - A fence that fails deactivates the TSO service, as after a failed RPC: no 
TSO is given out and no read is admitted on the watermark until a calibration 
has advanced the fence above every TSO given out before. The commit fails with 
the fence error then, and the answer of MetaService is logged first, so it is 
not lost.
   - The commit fails as before in every case: only what happens to its TSO 
changes.
   
   #### Results
   
   | Answer of MetaService to `commit_txn` | Before this PR | After this PR |
   | --- | --- | --- |
   | `KV_TXN_COMMIT_ERR` (the FDB commit timed out, or failed with an error 
MetaService does not classify) | TSO given up at once | Fence advanced to the 
TSO, then the TSO given up |
   | The RPC failed | Fence advanced to the TSO, then the TSO given up | 
Unchanged |
   | `KV_TXN_MAYBE_COMMITTED`, `KV_TXN_TOO_OLD` and the other errors | TSO 
given up at once | Unchanged |
   | `OK`, `TXN_ALREADY_VISIBLE`, `TXN_ALREADY_ABORTED` | Transaction finished 
| Unchanged |
   
   The cost stays on that error path: one more MetaService RPC, and the commits 
in flight with a TSO at or below the fence are rejected once with 
`TXN_COMMIT_TSO_EXPIRED` and retried with a new TSO, as after a failed RPC.
   
   #### Classes, and how they call each other
   
   - `CloudGlobalTransactionMgr.commitTxn`: the new branch for 
`KV_TXN_COMMIT_ERR`.
   - `CloudCommittedTsoTest`: the new 
`testKvCommitErrorIsFencedButDefiniteFailureIsReleased`.
   
   ```
   CloudGlobalTransactionMgr.commitTxn
     |-- MetaServiceProxy.commitTxn  -> answer, or an exception
     |-- RPC failed, or KV_TXN_COMMIT_ERR (new) -> 
TSOService.fenceAndAbandonCommitTso
     |       |-- GlobalTransactionMgr.advanceTsoFence(tso)  then  
TSOTransactionTracker.abandonCommitTso
     |       `-- the fence failed: TSOService.deactivate, and the commit fails 
with the fence error
     |-- KV_TXN_MAYBE_COMMITTED, other errors          -> 
TSOService.abandonCommitTso
     `-- OK, TXN_ALREADY_VISIBLE, TXN_ALREADY_ABORTED  -> 
TSOService.markTxnFinished
   ```
   
   Not changed: MetaService, which still answers a timed out commit with 
`KV_TXN_COMMIT_ERR`, and the handling of `KV_TXN_MAYBE_COMMITTED`.
   
   ### Release note
   
   Fix a bounded incremental read (`@incr`) in cloud mode that could miss a 
transaction whose commit timed out in MetaService.
   
   ### 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?  -->
   
       
`CloudCommittedTsoTest#testKvCommitErrorIsFencedButDefiniteFailureIsReleased`: 
`KV_TXN_COMMIT_ERR` advances the fence before the TSO is given up and still 
fails the commit; a fence that fails fails the commit with the fence error and 
gives nothing up; `KV_TXN_TOO_OLD` still gives the TSO up without a fence. It 
fails on the code before this PR. The cloud transaction and TSO test classes 
(`org/apache/doris/cloud/transaction/*Test` and `org/apache/doris/tso/*Test`, 7 
classes, 133 tests) pass.
   
   - Behavior changed:
       - [ ] No.
       - [x] Yes. <!-- Explain the behavior change -->
   
       A commit that MetaService answers with `KV_TXN_COMMIT_ERR` costs one 
more MetaService RPC, and the commits in flight at or below its TSO are retried 
once with a new TSO. If that fence fails, the TSO service deactivates until it 
is calibrated again, as after a failed commit RPC.
   
   - 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