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: TwoPhaseBusinessAction coexist with GlobalTransactional #6331

Merged
merged 8 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6232](https://github.com/apache/incubator-seata/pull/6232)] convert to utf8mb4 if mysql column is json type
- [[#6278](https://github.com/apache/incubator-seata/pull/6278)] fix ProtocolV1SerializerTest failed
- [[#6324](https://github.com/apache/incubator-seata/pull/6324)] fix Parse protocol file failed
- [[#6331](https://github.com/apache/incubator-seata/pull/6331)] fixed the problem that TCC nested transactions cannot add TwoPhaseBusinessAction and GlobalTransactional annotations at the same time
- [[#6354](https://github.com/apache/incubator-seata/pull/6354)] fix dynamic degradation does not work properly
- [[#6363](https://github.com/apache/incubator-seata/pull/6363)] fix known problems of docker image
- [[#6372](https://github.com/apache/incubator-seata/pull/6372)] fix initializing the sql file postgresql.sql index name conflict
Expand Down
1 change: 1 addition & 0 deletions changes/zh-cn/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- [[#6232](https://github.com/apache/incubator-seata/pull/6232)] 修复在mysql的json类型下出现Cannot create a JSON value from a string with CHARACTER SET 'binary'问题
- [[#6278](https://github.com/apache/incubator-seata/pull/6278)] 修复 ProtocolV1SerializerTest 失败问题
- [[#6324](https://github.com/apache/incubator-seata/pull/6324)] 修复 Parse protocol file failed
- [[#6331](https://github.com/apache/incubator-seata/pull/6331)] 修复TCC嵌套事务不能同时添加TwoPhaseBusinessAction和GlobalTransactional两个注解的问题
- [[#6354](https://github.com/apache/incubator-seata/pull/6354)] 修复动态升降级不能正常工作问题
- [[#6363](https://github.com/apache/incubator-seata/pull/6363)] 修复docker镜像中的已知问题
- [[#6372](https://github.com/apache/incubator-seata/pull/6372)] 修复初始化sql文件postgresql.sql 索引名称冲突问题
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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.integration.tx.api.interceptor;

import java.lang.reflect.Method;
import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;


public class NestInterceptorHandlerWrapper implements InvocationWrapper {

private ProxyInvocationHandler proxyInvocationHandler;

private InvocationWrapper invocation;

public NestInterceptorHandlerWrapper(ProxyInvocationHandler proxyInvocationHandler, InvocationWrapper invocation) {
this.proxyInvocationHandler = proxyInvocationHandler;
this.invocation = invocation;
}

@Override
public Method getMethod() {
return invocation.getMethod();
}

@Override
public Object getProxy() {
return invocation.getProxy();
}

@Override
public Object getTarget() {
return invocation.getTarget();
}

@Override
public Object[] getArguments() {
return invocation.getArguments();
}

@Override
public Object proceed() throws Throwable {
return proxyInvocationHandler.invoke(invocation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.integration.tx.api.interceptor.NestInterceptorHandlerWrapper;


public abstract class AbstractProxyInvocationHandler implements ProxyInvocationHandler {
Expand All @@ -26,11 +27,16 @@ public abstract class AbstractProxyInvocationHandler implements ProxyInvocationH

protected int order = Integer.MAX_VALUE;

protected ProxyInvocationHandler nextInvocationHandlerChain;

@Override
public Object invoke(InvocationWrapper invocation) throws Throwable {
if (CollectionUtils.isNotEmpty(getMethodsToProxy()) && !getMethodsToProxy().contains(invocation.getMethod().getName())) {
return invocation.proceed();
}
if (nextInvocationHandlerChain != null) {
invocation = new NestInterceptorHandlerWrapper(nextInvocationHandlerChain, invocation);
}
return doInvoke(invocation);
}

Expand All @@ -44,4 +50,8 @@ public int getOrder() {
return this.order;
}

@Override
public void setNextProxyInvocationHandler(ProxyInvocationHandler next) {
this.nextInvocationHandlerChain = next;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
*/
package org.apache.seata.integration.tx.api.interceptor.handler;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.google.common.eventbus.Subscribe;
import org.apache.seata.common.exception.ShouldNeverHappenException;
import org.apache.seata.common.thread.NamedThreadFactory;
Expand Down Expand Up @@ -51,15 +60,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.apache.seata.common.DefaultValues.DEFAULT_DISABLE_GLOBAL_TRANSACTION;
import static org.apache.seata.common.DefaultValues.DEFAULT_GLOBAL_TRANSACTION_TIMEOUT;
import static org.apache.seata.common.DefaultValues.DEFAULT_TM_DEGRADE_CHECK;
Expand Down Expand Up @@ -410,4 +410,9 @@ public SeataInterceptorPosition getPosition() {
return SeataInterceptorPosition.BeforeTransaction;
}


@Override
public String type() {
return "GlobalTransactional";
funky-eyes marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ public interface ProxyInvocationHandler extends SeataInterceptor {

SeataInterceptorPosition getPosition();

String type();

default int order() {
return 0;
}

void setNextProxyInvocationHandler(ProxyInvocationHandler next);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@
*/
package org.apache.seata.integration.tx.api.interceptor.parser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.seata.common.loader.EnhancedServiceLoader;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;

import java.util.ArrayList;
import java.util.List;

/**
* @author leezongjie
*/
Expand Down Expand Up @@ -53,15 +57,46 @@ protected void initInterfaceParser() {
}
}

/**
* Create an interceptor chain that supports adding multiple interceptors.Create an interceptor chain that supports adding multiple interceptors.
* The entry order of the facets can be specified through {@link ProxyInvocationHandler # order()}.
* It is not allowed to load multiple interceptors of the same type, such as two-stage annotations for TCC and Saga that cannot exist simultaneously. The type can be specified through {@link ProxyInvocationHandler # type()}.It is not allowed to load multiple interceptors of the same type, such as two-stage annotations for TCC and Saga that cannot exist simultaneously. The type can be specified through {@link ProxyInvocationHandler # type()}.
*
* @param target
* @param objectName
* @return
* @throws Exception
*/
@Override
public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception {
List<ProxyInvocationHandler> invocationHandlerList = new ArrayList<>();
Set<String> invocationHandlerRepeatCheck = new HashSet<>();

for (InterfaceParser interfaceParser : ALL_INTERFACE_PARSERS) {
ProxyInvocationHandler proxyInvocationHandler = interfaceParser.parserInterfaceToProxy(target, objectName);
if (proxyInvocationHandler != null) {
return proxyInvocationHandler;
if (!invocationHandlerRepeatCheck.add(proxyInvocationHandler.type())) {
throw new RuntimeException("there is already an annotation of type " + proxyInvocationHandler.type() + " for class: " + target.getClass().getName());
}
invocationHandlerList.add(proxyInvocationHandler);
}
}
return null;

Collections.sort(invocationHandlerList, Comparator.comparingInt(ProxyInvocationHandler::order));

ProxyInvocationHandler result = null;
funky-eyes marked this conversation as resolved.
Show resolved Hide resolved
ProxyInvocationHandler last = null;
for (ProxyInvocationHandler proxyInvocationHandler : invocationHandlerList) {
if (result == null) {
result = proxyInvocationHandler;
}
if (last != null) {
last.setNextProxyInvocationHandler(proxyInvocationHandler);
}
last = proxyInvocationHandler;
}

return result;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.seata.common.ConfigurationKeys;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.common.util.ReflectionUtil;
Expand All @@ -31,7 +30,6 @@
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.apache.seata.tm.api.FailureHandlerHolder;


public class GlobalTransactionalInterceptorParser implements InterfaceParser {

protected final Set<String> methodsToProxy = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.seata.common.Constants;
import org.apache.seata.common.DefaultValues;
import org.apache.seata.common.holder.ObjectHolder;
Expand All @@ -37,11 +36,9 @@
import org.apache.seata.integration.tx.api.interceptor.handler.AbstractProxyInvocationHandler;
import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.slf4j.MDC;

import static org.apache.seata.common.ConfigurationKeys.TCC_ACTION_INTERCEPTOR_ORDER;
import static org.apache.seata.common.Constants.BEAN_NAME_SPRING_FENCE_CONFIG;


public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler {

private static final int ORDER_NUM = ConfigurationFactory.getInstance().getInt(TCC_ACTION_INTERCEPTOR_ORDER,
Expand Down Expand Up @@ -167,4 +164,13 @@ public SeataInterceptorPosition getPosition() {
return SeataInterceptorPosition.Any;
}

@Override
public int order() {
return 1;
}

@Override
public String type() {
return "twoPhaseAnnotation";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.apache.seata.common.util.ReflectionUtil;
import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;
import org.apache.seata.integration.tx.api.interceptor.parser.DefaultResourceRegisterParser;
Expand All @@ -34,7 +33,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class TccActionInterceptorParser implements InterfaceParser {

private static final Logger LOGGER = LoggerFactory.getLogger(TccActionInterceptorParser.class);
Expand Down
85 changes: 85 additions & 0 deletions tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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.rm.tcc;

import org.apache.seata.core.model.BranchType;

public class BranchSessionMock {

private String xid;

private long branchId;

private String resourceGroupId;

private String resourceId;


private BranchType branchType;


private String applicationData;


public String getXid() {
return xid;
}

public void setXid(String xid) {
this.xid = xid;
}

public long getBranchId() {
return branchId;
}

public void setBranchId(long branchId) {
this.branchId = branchId;
}

public String getResourceGroupId() {
return resourceGroupId;
}

public void setResourceGroupId(String resourceGroupId) {
this.resourceGroupId = resourceGroupId;
}

public String getResourceId() {
return resourceId;
}

public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}

public BranchType getBranchType() {
return branchType;
}

public void setBranchType(BranchType branchType) {
this.branchType = branchType;
}

public String getApplicationData() {
return applicationData;
}

public void setApplicationData(String applicationData) {
this.applicationData = applicationData;
}
}
Loading
Loading