-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[fix][txn] fix txn coordinator recover handle committing and aborting txn race condition. #19201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[fix][txn] fix txn coordinator recover handle committing and aborting txn race condition. #19201
Conversation
|
Maybe there is a better way to fix it? from |
|
if the TC does not exist in the broker, the op doesn't need to retry. #18924 may has fix this problem |
I have include this PR in my test enviroment, and exceptions above have been throwed. That PR do not gurantee that TC have been put into |
|
pulsar/pulsar-broker/src/main/java/org/apache/pulsar/broker/TransactionMetadataStoreService.java Lines 136 to 137 in 246c270
the future thenAccept change the executing thread, so the problem has never been truth fixed.
so its better to change code like this can slove this problem |
good idea. i have changed the patch. |
|
@thetumbled It looks like the change is not about the issue that you described in the PR details. When reading the motivation of the PR, I thought it was related to the transaction buffer snapshot, but after checking the changes, it looks like the fix is for the transaction coordinator. |
When I was troubleshooting why transaction recovery took a long time, I found that the root cause is some transactions cannot be terminated though exceeding timeout, which leads to subsequent phenomena. |
| completableFuture.complete(null); | ||
| tcLoadSemaphore.release(); | ||
| })).exceptionally(e -> { | ||
| completableFuture.complete(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@congbobo184 @thetumbled Sorry, I didn't get the key point of the problem. The completableFuture is completed by the same thread of executing stores.put(tcId, store); Why will we have race condition here? The client-side should send the end transaction command after completing the TC connect stage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two thread pools org.apache.pulsar.transaction.coordinator.impl.MLTransactionMetadataStore#internalPinnedExecutor and org.apache.pulsar.broker.TransactionMetadataStoreService#internalPinnedExecutor. They are different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but before we complete the completableFuture here, we have added the item to the map. Why the subsequent request is not able to get from the map? The subsequent request only happened after the completableFuture was done, right? And the map is a ConcurrentHashMap, so what is the race condition here? Could you please provide more details about the race condition? How does it happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The completableFuture return by openTransactionMetadataStore(tcId) is completed by following code in thread MLTransactionMetadataStore#internalPinnedExecutor.
**completableFuture.complete(MLTransactionMetadataStore.this);**
recoverTracker.handleCommittingAndAbortingTransaction();
Once the completableFuture is completed, stores.put will be executed in another thread TransactionMetadataStoreService#internalPinnedExecutor.
openTransactionMetadataStore(tcId).thenAccept((store) -> internalPinnedExecutor.execute(() -> {
stores.put(tcId, store);
So, we may execute recoverTracker.handleCommittingAndAbortingTransaction() before execute stores.put(tcId, store).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Essentially this is a circular dependency problem.
TransactionMetadataStoreService.handleTcClientConnect -> MLTransactionMetadataStore.init -> TransactionRecoverTracker.handleCommittingAndAbortingTransaction -> TransactionMetadataStoreService.handleTcClientConnect
It looks like we need to ensure some state is changed in TransactionMetadataStoreService during init MLTransactionMetadataStore.
IMO, we should refactor this part finally to move the recoverTracker.handleCommittingAndAbortingTransaction(); to the TransactionMetadataStoreService to decouple the mutual state dependence.
@congbobo184 @liangyepianzhou WDYT?
It's hard to understand why the map put operation should be executed out of the internalPinnedExecutor while reading the code. This may present challenges for future maintenance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
openTransactionMetadataStore(tcId) can return MutablePair<store, recoverTracker> or after openTransactionMetadataStore(tcId) then init return the recoverTracker. I prefer to use the second way, in this way the logical more clear, after store init the tracker need to do something to handle the legacy the committing and abort transactions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the first solution is more concise, and i have implement it.
As for the second approach, do you means that move init method out of openTransactionMetadataStore method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, in the second way can completely decoupled. @codelipenghui WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I haven't got the point of openTransactionMetadataStore(tcId) then init return the recoverTracker, @congbobo184 Can you share the link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 108 in 3bab099
| public CompletableFuture<TransactionMetadataStore> init(TransactionRecoverTracker recoverTracker) { |
change to
public CompletableFuture<TransactionRecoverTracker> init()
openTransactionMetadataStore(tcId) only return the store,
then the store can add a interface public CompletableFuture<TransactionRecoverTracker> init(),
TransactionMetadataStoreService can invoke the store.init() return TransactionRecoverTracker
init completely, recoverTracker can do
Line 47 in 3bab099
| void appendOpenTransactionToTimeoutTracker(); |
Line 52 in 3bab099
| void handleCommittingAndAbortingTransaction(); |
in the
TransactionMetadataStoreService
…ice to decouple the mutual state dependence.
pulsar-broker/src/main/java/org/apache/pulsar/broker/TransactionMetadataStoreService.java
Outdated
Show resolved
Hide resolved
codelipenghui
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me now.
I just left some minor comments.
...inator/src/main/java/org/apache/pulsar/transaction/coordinator/TransactionMetadataStore.java
Outdated
Show resolved
Hide resolved
pulsar-broker/src/main/java/org/apache/pulsar/broker/TransactionMetadataStoreService.java
Show resolved
Hide resolved
449d962 to
e9f2f30
Compare
|
@congbobo184 @liangyepianzhou Please help review again. |
pulsar-broker/src/main/java/org/apache/pulsar/broker/TransactionMetadataStoreService.java
Outdated
Show resolved
Hide resolved
Codecov Report
@@ Coverage Diff @@
## master #19201 +/- ##
=============================================
+ Coverage 48.96% 60.71% +11.74%
- Complexity 7300 25533 +18233
=============================================
Files 424 1895 +1471
Lines 45473 137527 +92054
Branches 4672 15099 +10427
=============================================
+ Hits 22268 83503 +61235
- Misses 20698 46300 +25602
- Partials 2507 7724 +5217
Flags with carried forward coverage won't be shown. Click here to find out more.
|
pulsar-broker/src/main/java/org/apache/pulsar/broker/TransactionMetadataStoreService.java
Show resolved
Hide resolved
… txn race condition. (#19201) Fixes #19200 transaction lasted for long time and will not be aborted, which cause TB's MaxReadPosition do not move and will not take snapshot. With an old snapshot, TB will read a lot of entry while doing recovery. In worst cases, there are 30 minutes of unavailable time with Topics. avoid concurrent execution.
… txn race condition. (#19201) Fixes #19200 transaction lasted for long time and will not be aborted, which cause TB's MaxReadPosition do not move and will not take snapshot. With an old snapshot, TB will read a lot of entry while doing recovery. In worst cases, there are 30 minutes of unavailable time with Topics. avoid concurrent execution. (cherry picked from commit 96f4161)
… txn race condition. (apache#19201) Fixes apache#19200 transaction lasted for long time and will not be aborted, which cause TB's MaxReadPosition do not move and will not take snapshot. With an old snapshot, TB will read a lot of entry while doing recovery. In worst cases, there are 30 minutes of unavailable time with Topics. avoid concurrent execution. (cherry picked from commit 96f4161) (cherry picked from commit 5dd13ec)
|
@thetumbled Can you help cherry-pick this PR to branch-2.9? |
ok. |
…ng and aborting txn race condition. apache#19201 (apache#19699) Cherry-pick: apache#19201
Fixes #19200
Motivation
transaction lasted for long time and will not be aborted, which cause TB's MaxReadPosition do not move and will not take snapshot. With an old snapshot, TB will read a lot of entry while doing recovery.
In worst cases, there are 30 minutes of unavailable time with Topics.
Modifications
makeCoordinatorNotFoundExceptionretryable.avoid concurrent execution.
Verifying this change
(Please pick either of the following options)
This change is a trivial rework / code cleanup without any test coverage.
Does this pull request potentially affect one of the following parts:
If the box was checked, please highlight the changes
Documentation
docdoc-requireddoc-not-neededdoc-completeMatching PR in forked repository
PR in forked repository: thetumbled#12