Skip to content

Commit

Permalink
optimize: tcc compatible (#6387)
Browse files Browse the repository at this point in the history
  • Loading branch information
wt-better committed Mar 8, 2024
1 parent d47a5d5 commit 4027ff8
Show file tree
Hide file tree
Showing 29 changed files with 1,168 additions and 452 deletions.
1 change: 1 addition & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6386](https://github.com/apache/incubator-seata/pull/6386)] replace `byte-buddy` to JDK proxy in `ConfigurationCache`
- [[#6391](https://github.com/apache/incubator-seata/pull/6091)] forbid duplicate registration of TCC resources
- [[#6393](https://github.com/apache/incubator-seata/pull/6393)] determine the version before sync metadata and add retry mechanism
- [[#6387](https://github.com/apache/incubator-seata/pull/6387)] optimize tcc use compatible

### refactor:
- [[#6269](https://github.com/apache/incubator-seata/pull/6269)] standardize Seata Exception
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 @@ -111,6 +111,7 @@
- [[#6386](https://github.com/apache/incubator-seata/pull/6386)]`ConfigurationCache` 类中,将 `byte-buddy` 替换为JDK代理
- [[#6391](https://github.com/apache/incubator-seata/pull/6091)] 禁止重复注册TCC资源
- [[#6393](https://github.com/apache/incubator-seata/pull/6393)] 元数据同步前判断版本,并增加重试功能
- [[#6387](https://github.com/apache/incubator-seata/pull/6387)] 优化tcc使用兼容


### refactor:
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package io.seata.integration.tx.api.interceptor;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import org.apache.seata.rm.tcc.api.ParamType;

Expand All @@ -30,6 +31,34 @@
@Deprecated
public class ActionInterceptorHandler extends org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler {

protected BusinessActionContext getOrCreateActionContextAndResetToArguments(Class<?>[] parameterTypes, Object[] arguments) {
BusinessActionContext actionContext = null;

// get the action context from arguments
int argIndex = 0;
for (Class<?> parameterType : parameterTypes) {
if (BusinessActionContext.class.isAssignableFrom(parameterType)) {
actionContext = (BusinessActionContext) arguments[argIndex];
if (actionContext == null) {
// If the action context exists in arguments but is null, create a new one and reset the action context to the arguments
actionContext = new BusinessActionContext();
arguments[argIndex] = actionContext;
} else {
// Reset the updated, avoid unnecessary reporting
actionContext.setUpdated(null);
}
break;
}
argIndex++;
}

// if null, create a new one
if (actionContext == null) {
actionContext = new BusinessActionContext();
}
return actionContext;
}


/**
* Extracting context data from parameters, add them to the context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@
* parameter's name. Synonym for {@link #paramName()}.
*
* @return the name of the param or field
* @see org.apache.seata.spring.interceptor.ActionContextUtil#getParamNameFromAnnotation
* @see io.seata.integration.tx.api.interceptor.ActionContextUtil#getParamNameFromAnnotation
*/
String value() default "";

/**
* parameter's name. Synonym for {@link #value()}.
*
* @return the name of the param or field
* @see org.apache.seata.spring.interceptor.ActionContextUtil#getParamNameFromAnnotation
* @see io.seata.integration.tx.api.interceptor.ActionContextUtil#getParamNameFromAnnotation
*/
String paramName() default "";

Expand All @@ -54,7 +54,7 @@
* Specify the index of the parameter in the List
*
* @return the index of the List
* @see org.apache.seata.spring.interceptor.ActionContextUtil#getByIndex
* @see io.seata.integration.tx.api.interceptor.ActionContextUtil#getByIndex
*/
int index() default -1;

Expand All @@ -63,8 +63,8 @@
* if {@code index >= 0}, the object get from the List and then do get the parameter from the property of the object
*
* @return the boolean
* @see org.apache.seata.spring.interceptor.ActionContextUtil#loadParamByAnnotationAndPutToContext
* @see org.apache.seata.spring.interceptor.ActionContextUtil#fetchContextFromObject
* @see io.seata.integration.tx.api.interceptor.ActionContextUtil#loadParamByAnnotationAndPutToContext
* @see io.seata.integration.tx.api.interceptor.ActionContextUtil#fetchContextFromObject
*/
boolean isParamInProperty() default false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,209 +16,52 @@
*/
package io.seata.rm.tcc.interceptor;

import io.seata.core.context.RootContext;
import io.seata.core.model.BranchType;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.apache.seata.common.Constants;
import org.apache.seata.common.holder.ObjectHolder;
import org.apache.seata.common.util.ReflectionUtil;
import org.apache.seata.integration.tx.api.fence.config.CommonFenceConfig;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.integration.tx.api.interceptor.TwoPhaseBusinessActionParam;
import org.slf4j.MDC;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.apache.seata.common.Constants.BEAN_NAME_SPRING_FENCE_CONFIG;
import io.seata.integration.tx.api.interceptor.ActionInterceptorHandler;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.apache.seata.common.Constants;
import org.apache.seata.integration.tx.api.interceptor.TwoPhaseBusinessActionParam;

public class TccActionInterceptorHandler extends org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler {

public TccActionInterceptorHandler(Object targetBean, Set<String> methodsToProxy) {
super(targetBean, methodsToProxy);
actionInterceptorHandler = new ActionInterceptorHandler();
}

@Override
protected Object doInvoke(InvocationWrapper invocation) throws Throwable {
if (!RootContext.inGlobalTransaction() || RootContext.inSagaBranch()) {
//not in transaction, or this interceptor is disabled
return invocation.proceed();
}
Method method = invocation.getMethod();
TwoPhaseBusinessAction businessAction = parseAnnotation(method);

//try method
if (businessAction != null) {
//save the xid
String xid = RootContext.getXID();
//save the previous branchType
BranchType previousBranchType = RootContext.getBranchType();
//if not TCC, bind TCC branchType
if (BranchType.TCC != previousBranchType) {
RootContext.bindBranchType(BranchType.TCC);
}
try {
TwoPhaseBusinessActionParam businessActionParam = new TwoPhaseBusinessActionParam();
businessActionParam.setActionName(businessAction.name());
businessActionParam.setDelayReport(businessAction.isDelayReport());
businessActionParam.setUseCommonFence(businessAction.useTCCFence());
businessActionParam.setBranchType(org.apache.seata.core.model.BranchType.TCC);
Map<String, Object> businessActionContextMap = new HashMap<>(4);
//the phase two method name
businessActionContextMap.put(Constants.COMMIT_METHOD, businessAction.commitMethod());
businessActionContextMap.put(Constants.ROLLBACK_METHOD, businessAction.rollbackMethod());
businessActionContextMap.put(Constants.ACTION_NAME, businessAction.name());
businessActionContextMap.put(Constants.USE_COMMON_FENCE, businessAction.useTCCFence());
businessActionParam.setBusinessActionContext(businessActionContextMap);
//Handler the TCC Aspect, and return the business result
return actionInterceptorHandler.proceed(method, invocation.getArguments(), xid, businessActionParam,
invocation::proceed);
} finally {
//if not TCC, unbind branchType
if (BranchType.TCC != previousBranchType) {
RootContext.unbindBranchType();
}
//MDC remove branchId
MDC.remove(org.apache.seata.core.context.RootContext.MDC_KEY_BRANCH_ID);
}
}

//not TCC try method
return invocation.proceed();
}

private TwoPhaseBusinessAction parseAnnotation(Method methodKey) throws NoSuchMethodException {
TwoPhaseBusinessAction result = convertIoSeata(parseAnnotationCache.computeIfAbsent(methodKey, method -> {
TwoPhaseBusinessAction businessAction = method.getAnnotation(TwoPhaseBusinessAction.class);
if (businessAction == null && targetBean.getClass() != null) {
Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(targetBean.getClass());
if (interfaceClasses != null) {
for (Class<?> interClass : interfaceClasses) {
try {
Method m = interClass.getMethod(method.getName(), method.getParameterTypes());
businessAction = m.getAnnotation(TwoPhaseBusinessAction.class);
if (businessAction != null) {
// init common fence clean task if enable useTccFence
initCommonFenceCleanTask(businessAction);
break;
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
}
return convertApacheSeata(businessAction);
}));
return result;
protected Class<? extends Annotation> getAnnotationClass() {
return TwoPhaseBusinessAction.class;
}

private org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction convertApacheSeata(TwoPhaseBusinessAction twoPhaseBusinessAction) {
org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction result = new org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction() {

@Override
public Class<? extends Annotation> annotationType() {
return org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction.class;
}

@Override
public String name() {
return twoPhaseBusinessAction.name();
}

@Override
public String commitMethod() {
return twoPhaseBusinessAction.commitMethod();
}

@Override
public String rollbackMethod() {
return twoPhaseBusinessAction.rollbackMethod();
}

@Override
public boolean isDelayReport() {
return twoPhaseBusinessAction.isDelayReport();
}

@Override
public boolean useTCCFence() {
return twoPhaseBusinessAction.useTCCFence();
}

@Override
public Class<?>[] commitArgsClasses() {
return twoPhaseBusinessAction.commitArgsClasses();
}

@Override
public Class<?>[] rollbackArgsClasses() {
return twoPhaseBusinessAction.rollbackArgsClasses();
}
};
return result;
}

private TwoPhaseBusinessAction convertIoSeata(org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction twoPhaseBusinessAction) {
TwoPhaseBusinessAction result = new TwoPhaseBusinessAction() {
@Override
public Class<? extends Annotation> annotationType() {
return TwoPhaseBusinessAction.class;
}

@Override
public String name() {
return twoPhaseBusinessAction.name();
}

@Override
public String commitMethod() {
return twoPhaseBusinessAction.commitMethod();
}

@Override
public String rollbackMethod() {
return twoPhaseBusinessAction.rollbackMethod();
}

@Override
public boolean isDelayReport() {
return twoPhaseBusinessAction.isDelayReport();
}

@Override
public boolean useTCCFence() {
return twoPhaseBusinessAction.useTCCFence();
}

@Override
public Class<?>[] commitArgsClasses() {
return twoPhaseBusinessAction.commitArgsClasses();
}

@Override
public Class<?>[] rollbackArgsClasses() {
return twoPhaseBusinessAction.rollbackArgsClasses();
}
};
return result;
}


private void initCommonFenceCleanTask(TwoPhaseBusinessAction twoPhaseBusinessAction) {
CommonFenceConfig commonFenceConfig = (CommonFenceConfig) ObjectHolder.INSTANCE.getObject(BEAN_NAME_SPRING_FENCE_CONFIG);
if (commonFenceConfig == null || commonFenceConfig.getInitialized().get()) {
return;
}
if (twoPhaseBusinessAction != null && twoPhaseBusinessAction.useTCCFence()) {
if (commonFenceConfig.getInitialized().compareAndSet(false, true)) {
// init common fence clean task if enable useTccFence
commonFenceConfig.init();
}
@Override
protected boolean parserCommonFenceConfig(Annotation annotation) {
if (annotation == null) {
return false;
}
TwoPhaseBusinessAction businessAction = (TwoPhaseBusinessAction) annotation;
return businessAction.useTCCFence();
}

@Override
protected TwoPhaseBusinessActionParam createTwoPhaseBusinessActionParam(Annotation annotation) {
TwoPhaseBusinessAction businessAction = (TwoPhaseBusinessAction) annotation;
TwoPhaseBusinessActionParam businessActionParam = new TwoPhaseBusinessActionParam();
businessActionParam.setActionName(businessAction.name());
businessActionParam.setDelayReport(businessAction.isDelayReport());
businessActionParam.setUseCommonFence(businessAction.useTCCFence());
businessActionParam.setBranchType(getBranchType());
Map<String, Object> businessActionContextMap = new HashMap<>(4);
//the phase two method name
businessActionContextMap.put(Constants.COMMIT_METHOD, businessAction.commitMethod());
businessActionContextMap.put(Constants.ROLLBACK_METHOD, businessAction.rollbackMethod());
businessActionContextMap.put(Constants.ACTION_NAME, businessAction.name());
businessActionContextMap.put(Constants.USE_COMMON_FENCE, businessAction.useTCCFence());
businessActionParam.setBusinessActionContext(businessActionContextMap);
return businessActionParam;
}
}
Loading

0 comments on commit 4027ff8

Please sign in to comment.