Skip to content

Commit

Permalink
optimize: check relation of before status and after status when updat…
Browse files Browse the repository at this point in the history
…ing global session (#4629)
  • Loading branch information
Bughue committed Jun 10, 2022
1 parent 5729a38 commit 8f96afa
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 9 deletions.
3 changes: 3 additions & 0 deletions changes/en-us/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ The version is updated as follows:

### optimize:
- [[#4567](https://github.com/seata/seata/pull/4567)] Support where method condition(find_in_set)
- [[#4629](https://github.com/seata/seata/pull/4629)] check relation of before status and after status when updating global session


### test:
- [[#1234](https://github.com/seata/seata/pull/1234)] Please delete the sample later
Expand All @@ -34,6 +36,7 @@ Thanks to these contributors for their code commits. Please report an unintended

- [slievrly](https://github.com/slievrly)
- [doubleDimple](https://github.com/doubleDimple)
- [Bughue](https://github.com/Bughue)

Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.

Expand Down
2 changes: 2 additions & 0 deletions changes/zh-cn/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单

### optimize:
- [[#4567](https://github.com/seata/seata/pull/4567)] 支持where条件带函数find_in_set支持
- [[#4629](https://github.com/seata/seata/pull/4629)] 更新globalsession状态时检查更改前后的对应关系正确性

### test:
- [[#1234](https://github.com/seata/seata/pull/1234)] 样例,后续请删除
Expand All @@ -34,6 +35,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单

- [slievrly](https://github.com/slievrly)
- [doubleDimple](https://github.com/doubleDimple)
- [Bughue](https://github.com/Bughue)

同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ public void queueToRetryCommit() throws TransactionException {
public void queueToRetryRollback() throws TransactionException {
this.addSessionLifecycleListener(SessionHolder.getRetryRollbackingSessionManager());
GlobalStatus currentStatus = this.getStatus();
if (SessionHelper.isTimeoutGlobalStatus(currentStatus)) {
if (SessionStatusValidator.isTimeoutGlobalStatus(currentStatus)) {
this.setStatus(GlobalStatus.TimeoutRollbackRetrying);
} else {
this.setStatus(GlobalStatus.RollbackRetrying);
Expand Down
11 changes: 3 additions & 8 deletions server/src/main/java/io/seata/server/session/SessionHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public static void endRollbacked(GlobalSession globalSession, boolean retryGloba
GlobalStatus currentStatus = globalSession.getStatus();
boolean retryBranch =
currentStatus == GlobalStatus.TimeoutRollbackRetrying || currentStatus == GlobalStatus.RollbackRetrying;
if (isTimeoutGlobalStatus(currentStatus)) {
if (SessionStatusValidator.isTimeoutGlobalStatus(currentStatus)) {
globalSession.changeGlobalStatus(GlobalStatus.TimeoutRollbacked);
} else {
globalSession.changeGlobalStatus(GlobalStatus.Rollbacked);
Expand All @@ -192,7 +192,7 @@ public static void endRollbacked(GlobalSession globalSession, boolean retryGloba
*/
public static void endRollbackFailed(GlobalSession globalSession, boolean retryGlobal) throws TransactionException {
GlobalStatus currentStatus = globalSession.getStatus();
if (isTimeoutGlobalStatus(currentStatus)) {
if (SessionStatusValidator.isTimeoutGlobalStatus(currentStatus)) {
globalSession.changeGlobalStatus(GlobalStatus.TimeoutRollbackFailed);
} else {
globalSession.changeGlobalStatus(GlobalStatus.RollbackFailed);
Expand All @@ -202,12 +202,7 @@ public static void endRollbackFailed(GlobalSession globalSession, boolean retryG
MetricsPublisher.postSessionDoneEvent(globalSession, retryGlobal, false);
}

public static boolean isTimeoutGlobalStatus(GlobalStatus status) {
return status == GlobalStatus.TimeoutRollbacked
|| status == GlobalStatus.TimeoutRollbackFailed
|| status == GlobalStatus.TimeoutRollbacking
|| status == GlobalStatus.TimeoutRollbackRetrying;
}


/**
* Foreach global sessions.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed 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 io.seata.server.session;

import io.seata.core.model.GlobalStatus;

/**
* The type change status validator.
*
* @author Bughue
*/
public class SessionStatusValidator {

/**
* is timeout global status
*
* @param status the global session
*/
public static boolean isTimeoutGlobalStatus(GlobalStatus status) {
return status == GlobalStatus.TimeoutRollbacked
|| status == GlobalStatus.TimeoutRollbackFailed
|| status == GlobalStatus.TimeoutRollbacking
|| status == GlobalStatus.TimeoutRollbackRetrying;
}

/**
* is rollback global status
*
* @param status the global session
*/
public static boolean isRollbackGlobalStatus(GlobalStatus status) {
return status == GlobalStatus.Rollbacking
|| status == GlobalStatus.RollbackRetrying
|| status == GlobalStatus.Rollbacked
|| status == GlobalStatus.RollbackFailed
|| status == GlobalStatus.RollbackRetryTimeout;
}

/**
* is commit global status
*
* @param status the global session
*/
public static boolean isCommitGlobalStatus(GlobalStatus status) {
return status == GlobalStatus.Committing
|| status == GlobalStatus.AsyncCommitting
|| status == GlobalStatus.CommitRetrying
|| status == GlobalStatus.Committed
|| status == GlobalStatus.CommitFailed
|| status == GlobalStatus.CommitRetryTimeout;
}

/**
* check the relation of before status and after status
*
* @param before the global session
* @param after the global session
*/
public static boolean validateUpdateStatus(GlobalStatus before, GlobalStatus after) {
if (isTimeoutGlobalStatus(before) && isCommitGlobalStatus(after)) {
return false;
}
if (isCommitGlobalStatus(before) && isTimeoutGlobalStatus(after)) {
return false;
}
if (isRollbackGlobalStatus(before) && isCommitGlobalStatus(after)) {
return false;
}
if (isCommitGlobalStatus(before) && isRollbackGlobalStatus(after)) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.stream.Collectors;
import io.seata.config.Configuration;
import io.seata.config.ConfigurationFactory;
import io.seata.server.session.SessionStatusValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
Expand Down Expand Up @@ -326,6 +327,12 @@ private boolean updateGlobalTransactionDO(GlobalTransactionDO globalTransactionD
jedis.unwatch();
return true;
}
GlobalStatus before = GlobalStatus.get(Integer.parseInt(previousStatus));
GlobalStatus after = GlobalStatus.get(globalTransactionDO.getStatus());
if (!SessionStatusValidator.validateUpdateStatus(before, after)) {
throw new StoreException("Illegal changing of global status, update global transaction failed."
+ " beforeStatus[" + before.name() + "] cannot be changed to afterStatus[" + after.name() + "]");
}

String previousGmtModified = statusAndGmtModified.get(1);
Transaction multi = jedis.multi();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed 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 io.seata.server.session;

import io.seata.core.model.GlobalStatus;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

/**
* the type change status validator test
*
* @author Bughue
*/
@SpringBootTest
public class SessionStatusValidatorTest {

@Test
public void testValidateUpdateStatus(){
Assertions.assertEquals(true, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Begin, GlobalStatus.Committing));
Assertions.assertEquals(true, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Committing, GlobalStatus.Committed));

Assertions.assertEquals(false, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Committing, GlobalStatus.TimeoutRollbacking));
Assertions.assertEquals(false, SessionStatusValidator.validateUpdateStatus(GlobalStatus.TimeoutRollbacking, GlobalStatus.Committing));
Assertions.assertEquals(false, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Committing, GlobalStatus.Rollbacking));
Assertions.assertEquals(false, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Rollbacking, GlobalStatus.Committing));

Assertions.assertEquals(false, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Committed, GlobalStatus.Rollbacked));
Assertions.assertEquals(false, SessionStatusValidator.validateUpdateStatus(GlobalStatus.Committed, GlobalStatus.TimeoutRollbacking));

}
}

0 comments on commit 8f96afa

Please sign in to comment.