Skip to content
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

bugfix: fix ConcurrentModificationException in SessionConverter.convertBranchSession #6943

Merged
merged 9 commits into from
Oct 24, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Contributors are welcomed to join the Seata project. Please check [CONTRIBUTING]
* dev@seata.apache.org , for dev/user discussion. [subscribe](mailto:dev-subscribe@seata.apache.org), [unsubscribe](mailto:dev-unsubscribe@seata.apache.org), [archive](https://lists.apache.org/list.html?dev@seata.apache.org)
* Online chat:

| Dingtalk group | Wechat office account | QQ group | Wechat assistant |
| Dingtalk group | Wechat official account | QQ group | Wechat assistant |
|:---------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------:|
| <img src="https://seata.apache.org/zh-cn/assets/images/dingtalk-group-67f42c9466fb2268b6927bb16b549d6c.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-official-467d10305f5449e6b2096e65d23a9d02.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/qq-group-8d8a89699cdb9ba8818364069475ba96.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-f8a87a96973942b826e32d1aed9bc8d9.jpg" width="150" /> |

Expand Down
1 change: 1 addition & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6923](https://github.com/apache/incubator-seata/pull/6923)] Enhance 401 Error Handling by Refreshing Token
- [[#6925](https://github.com/apache/incubator-seata/pull/6925)] fix the issue in Raft model a follower's crash may lead to the continued use of expired tokens
- [[#6932](https://github.com/apache/incubator-seata/pull/6932)] when enabling local transactions, the lock contention failure in file & raft mode does not exit, leading to a lingering lock
- [[#6943](https://github.com/apache/incubator-seata/pull/6943)] fix the conversion error for `convertBranchSession` in concurrent environment.

### optimize:
- [[#6826](https://github.com/apache/incubator-seata/pull/6826)] remove the branch registration operation of the XA read-only transaction
Expand Down
2 changes: 1 addition & 1 deletion changes/zh-cn/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- [[#6923](https://github.com/apache/incubator-seata/pull/6923)] 增强 401 错误处理,通过刷新令牌
- [[#6925](https://github.com/apache/incubator-seata/pull/6925)] 修复Raft模式下,Follower崩溃可能导致Client继续使用过期令牌的问题
- [[#6932](https://github.com/apache/incubator-seata/pull/6932)] 修复开启本地事务时file&raft模式下锁争抢失败未退出导致可能出现残留锁

- [[#6943](https://github.com/apache/incubator-seata/pull/6943)] 修复并发状态下 `convertBranchSession` 转换报错问题

### optimize:
- [[#6826](https://github.com/apache/incubator-seata/pull/6826)] 移除只读XA事务的分支注册操作
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,10 @@ public static Set<BranchSessionVO> convertBranchSession(List<BranchSession> bran
return Collections.emptySet();
}

final Set<BranchSessionVO> result = new HashSet<>(branchSessions.size());
List<BranchSession> safeBranchSessions = new ArrayList<>(branchSessions);
final Set<BranchSessionVO> result = new HashSet<>(safeBranchSessions.size());

for (BranchSession session : branchSessions) {
for (BranchSession session : safeBranchSessions) {
result.add(new BranchSessionVO(
session.getXid(),
session.getTransactionId(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.seata.server.storage;
//
//import java.util.ArrayList;
//import java.util.ConcurrentModificationException;
//import java.util.List;
//import java.util.concurrent.CountDownLatch;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.atomic.AtomicBoolean;
//import org.apache.seata.core.model.BranchStatus;
//import org.apache.seata.core.model.BranchType;
//import org.apache.seata.server.session.BranchSession;
//import org.junit.jupiter.api.RepeatedTest;
//import org.junit.jupiter.api.extension.ExtendWith;
//import org.mockito.junit.jupiter.MockitoExtension;
//import org.springframework.boot.test.context.SpringBootTest;
//
//import static org.junit.jupiter.api.Assertions.assertFalse;
//
//@ExtendWith(MockitoExtension.class)
//@SpringBootTest
//public class SessionConverterTest {
// // Repeat 100 for adding success per
// @RepeatedTest(100)
// public void testConcurrentModificationException() throws InterruptedException {
// List<BranchSession> branchSessions = new ArrayList<>();
// for (int i = 0; i < 1000; i++) {
// branchSessions.add(createMockBranchSession(i));
// }
//
// CountDownLatch startLatch = new CountDownLatch(1);
// CountDownLatch endLatch = new CountDownLatch(2);
// AtomicBoolean exceptionThrown = new AtomicBoolean(false);
//
// ExecutorService executorService = Executors.newFixedThreadPool(2);
//
// // Thread for converting branch sessions
// executorService.submit(() -> {
// try {
// startLatch.await();
// for (int i = 0; i < 100; i++) {
// try {
// SessionConverter.convertBranchSession(branchSessions);
// } catch (ConcurrentModificationException e) {
// exceptionThrown.set(true);
// break;
// }
// }
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// } finally {
// endLatch.countDown();
// }
// });
//
// // Thread for modifying the list
// executorService.submit(() -> {
// try {
// startLatch.await();
// for (int i = 0; i < 1000; i++) {
// branchSessions.add(createMockBranchSession(1000 + i));
// if (i % 10 == 0) {
// branchSessions.remove(0);
// }
// }
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// } finally {
// endLatch.countDown();
// }
// });
// // Start both threads
// startLatch.countDown();
// // Wait for both threads to finish
// endLatch.await();
//
// executorService.shutdown();
//
// assertFalse(exceptionThrown.get(), "ConcurrentModificationException was not thrown");
// }
//
// private BranchSession createMockBranchSession(int id) {
// BranchSession session = new BranchSession();
// session.setXid("xid" + id);
// session.setTransactionId(id);
// session.setBranchId(id);
// session.setResourceGroupId("resourceGroup" + id);
// session.setResourceId("resource" + id);
// session.setBranchType(BranchType.AT);
// session.setStatus(BranchStatus.Registered);
// session.setClientId("client" + id);
// session.setApplicationData("data" + id);
// return session;
// }
//}
Loading