Seata源码分析之ResourceManager

                 目录

一、ResourceManager

二、AbstractResourceManager

三、DefaultResourceManager

四、TCCResourceManager

五、DataSourceManager

         六、AsyncWorker

七、UndoLogManager


一、ResourceManager

ResourceManager是seata的重要组件之一,RM负责管理分支数据资源的事务。它接口定义如下,实现ResourceManagerInbound以及ResourceManagerOutbound接口

public interface ResourceManager extends ResourceManagerInbound, ResourceManagerOutbound {

    // 注册一个resource至事务管理器上
    void registerResource(Resource resource);

    // 从事务管理器上取消注册一个resource
    void unregisterResource(Resource resource);

    // 获取所有管理的resource
    // @return resourceId -> Resource Map
    Map getManagedResources();

    // 获取此事务管理器的分支类型,有AT自动和TCC手动类型
    BranchType getBranchType();
}

ResourceManagerInbound接口提供给TC进行rpc调用的方法
public interface ResourceManagerInbound {

    // TM通知RM提交事务
    BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException;

    // TM通知RM回滚事务
    BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException;
}


提供rpc请求至TC
public interface ResourceManagerOutbound {

    // 请求注册分支resource
    Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, String applicationData, String lockKeys) throws
        TransactionException;

    // 报告分支状态
    void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status, String applicationData) throws TransactionException;

    // 锁住query
    boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys)
        throws TransactionException;
}

二、AbstractResourceManager

AbstractResourceManager实现ResourceManager提供模板方法

public abstract class AbstractResourceManager implements ResourceManager {

    // 创建BranchRegisterRequest请求,通过RmRpcClient客户端使用netty进行rpc调用,请求至TC,返回唯一的分支Id数据,
    // 超时或报错抛出TransactionException
    @Override
    public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, String applicationData, String lockKeys) throws TransactionException {
        try {
            BranchRegisterRequest request = new BranchRegisterRequest();
            request.setXid(xid);
            request.setLockKey(lockKeys);
            request.setResourceId(resourceId);
            request.setBranchType(branchType);
            request.setApplicationData(applicationData);

            BranchRegisterResponse response = (BranchRegisterResponse) RmRpcClient.getInstance().sendMsgWithResponse(request);
            if (response.getResultCode() == ResultCode.Failed) {
                throw new TransactionException(response.getTransactionExceptionCode(), "Response[" + response.getMsg() + "]");
            }
            return response.getBranchId();
        } catch (TimeoutException toe) {
            throw new TransactionException(TransactionExceptionCode.IO, "RPC Timeout", toe);
        } catch (RuntimeException rex) {
            throw new TransactionException(TransactionExceptionCode.BranchRegisterFailed, "Runtime", rex);
        }
    }

    // 创建BranchReportRequest请求,通过RmRpcClient客户端使用netty进行rpc调用,请求至TC,返回唯一的分支Id数据,
    // 超时或报错抛出TransactionException
    @Override
    public void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status, String applicationData) throws TransactionException {
        try {
            BranchReportRequest request = new BranchReportRequest();
            request.setXid(xid);
            request.setBranchId(branchId);
            request.setStatus(status);
            request.setApplicationData(applicationData);

            BranchReportResponse response = (BranchReportResponse) RmRpcClient.getInstance().sendMsgWithResponse(request);
            if (response.getResultCode() == ResultCode.Failed) {
                throw new TransactionException(response.getTransactionExceptionCode(), "Response[" + response.getMsg() + "]");
            }
        } catch (TimeoutException toe) {
            throw new TransactionException(TransactionExceptionCode.IO, "RPC Timeout", toe);
        } catch (RuntimeException rex) {
            throw new TransactionException(TransactionExceptionCode.BranchReportFailed, "Runtime", rex);
        }
    }

    // 默认返回false
    public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys) throws TransactionException {
        return false;
    }

    // 需子类实现
    public void unregisterResource(Resource resource) {
        throw new NotSupportYetException("unregister a resource");
    }

    // 调用RmRpcClient客户端,创建netty连接,进行rpc调用注册至全局tc
    public void registerResource(Resource resource) {
        RmRpcClient.getInstance().registerResource(resource.getResourceGroupId(), resource.getResourceId());
    }
}

三、DefaultResourceManager

DefaultResourceManager是虚拟的ResourceManager,适配所有的ResourceManager,所有方法调用都委派给对应负责的ResourceManager处理。

public class DefaultResourceManager implements ResourceManager {

    // 所有的ResourceManager缓存
    protected static Map resourceManagers
        = new ConcurrentHashMap<>();
    // 构造方法初始化
    private DefaultResourceManager() {
        initResourceManagers();
    }
    // 单例模式
    public static DefaultResourceManager get() {
        return SingletonHolder.INSTANCE;
    }
    public static void mockResourceManager(BranchType branchType, ResourceManager rm) {
        resourceManagers.put(branchType, rm);
    }
    // 初始化加载所有的ResourceManager,此处目前只有DataResourceManager和TCCResourceManager
    protected void initResourceManagers() {
        //init all resource managers
        List allResourceManagers = EnhancedServiceLoader.loadAll(ResourceManager.class);
        if (CollectionUtils.isNotEmpty(allResourceManagers)) {
            for (ResourceManager rm : allResourceManagers) {
                resourceManagers.put(rm.getBranchType(), rm);
            }
        }
    }
    @Override
    public BranchStatus branchCommit(BranchType branchType, String xid, long branchId,
                                     String resourceId, String applicationData)
        throws TransactionException {
        return getResourceManager(branchType).branchCommit(branchType, xid, branchId, resourceId, applicationData);
    }
    @Override
    public BranchStatus branchRollback(BranchType branchType, String xid, long branchId,
                                       String resourceId, String applicationData)
        throws TransactionException {
        return getResourceManager(branchType).branchRollback(branchType, xid, branchId, resourceId, applicationData);
    }
    @Override
    public Long branchRegister(BranchType branchType, String resourceId,
                               String clientId, String xid, String applicationData, String lockKeys)
        throws TransactionException {
        return getResourceManager(branchType).branchRegister(branchType, resourceId, clientId, xid, applicationData,
            lockKeys);
    }
    @Override
    public void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status,
                             String applicationData) throws TransactionException {
        getResourceManager(branchType).branchReport(branchType, xid, branchId, status, applicationData);
    }
    @Override
    public boolean lockQuery(BranchType branchType, String resourceId,
                             String xid, String lockKeys) throws TransactionException {
        return getResourceManager(branchType).lockQuery(branchType, resourceId, xid, lockKeys);
    }
    @Override
    public void registerResource(Resource resource) {
        getResourceManager(resource.getBranchType()).registerResource(resource);
    }
    @Override
    public void unregisterResource(Resource resource) {
        getResourceManager(resource.getBranchType()).unregisterResource(resource);
    }
    @Override
    public Map getManagedResources() {
        Map allResource = new HashMap();
        for (ResourceManager rm : resourceManagers.values()) {
            Map tempResources = rm.getManagedResources();
            if (tempResources != null) {
                allResource.putAll(tempResources);
            }
        }
        return allResource;
    }
    public ResourceManager getResourceManager(BranchType branchType) {
        ResourceManager rm = resourceManagers.get(branchType);
        if (rm == null) {
            throw new FrameworkException("No ResourceManager for BranchType:" + branchType.name());
        }
        return rm;
    }
    private static class SingletonHolder {
        private static DefaultResourceManager INSTANCE = new DefaultResourceManager();
    }
}

四、TCCResourceManager

TCCResourceManager继承AbstractResourceManager,管理TCC手动模式下resouce的注册,提交以及回滚等

public class TCCResourceManager extends AbstractResourceManager {

    // TCC resource的缓存
    private Map tccResourceCache = new ConcurrentHashMap();

    /**
     * Instantiates a new Tcc resource manager.
     */
    public TCCResourceManager() {
    }

    // 放入缓存,调用父类注册至全局TC
    @Override
    public void registerResource(Resource resource) {
        TCCResource tccResource = (TCCResource)resource;
        tccResourceCache.put(tccResource.getResourceId(), tccResource);
        super.registerResource(tccResource);
    }

    @Override
    public Map getManagedResources() {
        return tccResourceCache;
    }

    // TCC 分支提交
    public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId,
                                     String applicationData) throws TransactionException {
        // 根据resourceId获取TCCResource
        TCCResource tccResource = (TCCResource)tccResourceCache.get(resourceId);
        if (tccResource == null) {
            throw new ShouldNeverHappenException("TCC resource is not exist, resourceId:" + resourceId);
        }
	// 获取目标对象
        Object targetTCCBean = tccResource.getTargetBean();
	// 获取commit的方法
        Method commitMethod = tccResource.getCommitMethod();
        if (targetTCCBean == null || commitMethod == null) {
            throw new ShouldNeverHappenException("TCC resource is not available, resourceId:" + resourceId);
        }
        try {
            boolean result = false;
            //BusinessActionContext
            BusinessActionContext businessActionContext = getBusinessActionContext(xid, branchId, resourceId,
                applicationData);
	    // 提交方法反射调用
            Object ret = commitMethod.invoke(targetTCCBean, businessActionContext);
            LOGGER.info(
                "TCC resource commit result :" + ret + ", xid:" + xid + ", branchId:" + branchId + ", resourceId:"
                    + resourceId);
            if (ret != null) {
                if (ret instanceof TwoPhaseResult) {
                    result = ((TwoPhaseResult)ret).isSuccess();
                } else {
                    result = (boolean)ret;
                }
            }
	    // 返回是否成功
            return result ? BranchStatus.PhaseTwo_Committed : BranchStatus.PhaseTwo_CommitFailed_Retryable;
        } catch (Throwable t) {
            String msg = String.format("commit TCC resource error, resourceId: %s, xid: %s.", resourceId, xid);
            LOGGER.error(msg, t);
            throw new FrameworkException(t, msg);
        }
    }

    // TCC 分支回滚
    public BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId,
                                       String applicationData) throws TransactionException {
        // 根据resourceId获取TCCResource
        TCCResource tccResource = (TCCResource)tccResourceCache.get(resourceId);
        if (tccResource == null) {
            throw new ShouldNeverHappenException("TCC resource is not exist, resourceId:" + resourceId);
        }
	// 获取目标对象
        Object targetTCCBean = tccResource.getTargetBean();
	// 获取rollback的方法
        Method rollbackMethod = tccResource.getRollbackMethod();
        if (targetTCCBean == null || rollbackMethod == null) {
            throw new ShouldNeverHappenException("TCC resource is not available, resourceId:" + resourceId);
        }
        try {
            boolean result = false;
            //BusinessActionContext
            BusinessActionContext businessActionContext = getBusinessActionContext(xid, branchId, resourceId,
                applicationData);
	    // 反射调用方法
            Object ret = rollbackMethod.invoke(targetTCCBean, businessActionContext);
            LOGGER.info(
                "TCC resource rollback result :" + ret + ", xid:" + xid + ", branchId:" + branchId + ", resourceId:"
                    + resourceId);
            if (ret != null) {
                if (ret instanceof TwoPhaseResult) {
                    result = ((TwoPhaseResult)ret).isSuccess();
                } else {
                    result = (boolean)ret;
                }
            }
	    // 返回分支状态结果
            return result ? BranchStatus.PhaseTwo_Rollbacked : BranchStatus.PhaseTwo_RollbackFailed_Retryable;
        } catch (Throwable t) {
            String msg = String.format("rollback TCC resource error, resourceId: %s, xid: %s.", resourceId, xid);
            LOGGER.error(msg, t);
            throw new FrameworkException(t, msg);
        }
    }

    protected BusinessActionContext getBusinessActionContext(String xid, long branchId, String resourceId,
                                                             String applicationData) {
        //transfer tcc applicationData to Context
        Map tccContext = StringUtils.isBlank(applicationData) ? new HashMap() : (Map)JSON.parse(applicationData);
        Map actionContextMap = (Map)tccContext.get(Constants.TCC_ACTION_CONTEXT);
        BusinessActionContext businessActionContext = new BusinessActionContext(
            xid, String.valueOf(branchId), actionContextMap);
        businessActionContext.setActionName(resourceId);
        return businessActionContext;
    }

    // 当前为TCC分支管理器
    public BranchType getBranchType() {
        return BranchType.TCC;
    }
}

五、DataSourceManager

DataSourceManager继承AbstractResourceManager,管理数据库自动resouce的注册,提交以及回滚等

DataSourceManager继承AbstractResourceManager,管理数据库自动resouce的注册,提交以及回滚等
public class DataSourceManager extends AbstractResourceManager implements Initialize {

    private ResourceManagerInbound asyncWorker;
    private Map dataSourceCache = new ConcurrentHashMap<>();
    public void setAsyncWorker(ResourceManagerInbound asyncWorker) {
        this.asyncWorker = asyncWorker;
    }

    @Override
    public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys)
            throws TransactionException {
        try {
	    // 创建全球锁GlobalLockQueryRequest
            GlobalLockQueryRequest request = new GlobalLockQueryRequest();
            request.setXid(xid);
            request.setLockKey(lockKeys);
            request.setResourceId(resourceId);
            
            GlobalLockQueryResponse response = null;
	    // 如果当前线程context已经是在全球事务处理中,则发送请求
            if (RootContext.inGlobalTransaction()) {
                response = (GlobalLockQueryResponse) RmRpcClient.getInstance().sendMsgWithResponse(request);
            } else if (RootContext.requireGlobalLock()) {
	    // 或则开启了本地事务控制,能够获取到本地线程事务对象,进行负载均衡发送请求
                response = (GlobalLockQueryResponse) RmRpcClient.getInstance().sendMsgWithResponse(loadBalance(),
                        request, NettyClientConfig.getRpcRequestTimeout());
            } else {
                throw new RuntimeException("unknow situation!");
            }

            if (response.getResultCode() == ResultCode.Failed) {
                throw new TransactionException(response.getTransactionExceptionCode(),
                        "Response[" + response.getMsg() + "]");
            }
            return response.isLockable();
        } catch (TimeoutException toe) {
            throw new TransactionException(TransactionExceptionCode.IO, "RPC Timeout", toe);
        } catch (RuntimeException rex) {
            throw new TransactionException(TransactionExceptionCode.LockableCheckFailed, "Runtime", rex);
        }

    }

    // 负载均衡,获取注册中心的所有socket地址列表,返回负载均衡下的address
    private String loadBalance() {
        InetSocketAddress address = null;
        try {
            List inetSocketAddressList = RegistryFactory.getInstance().lookup(
                    TmRpcClient.getInstance().getTransactionServiceGroup());
            address = LoadBalanceFactory.getInstance().select(inetSocketAddressList);
        } catch (Exception ignore) {
            LOGGER.error(ignore.getMessage());
        }
        if (address == null) {
            throw new FrameworkException(NoAvailableService);
        }
        return NetUtil.toStringAddress(address);
    }

    public DataSourceManager() {
    }

    // 实例化异步处理器,提供异步删除undo日志的方法
    public void init() {
        AsyncWorker asyncWorker = new AsyncWorker();
        asyncWorker.init();
        initAsyncWorker(asyncWorker);
    }

    // 注册DataSourceProxy resource,放入缓存,同时告知TC进行注册
    public void registerResource(Resource resource) {
        DataSourceProxy dataSourceProxy = (DataSourceProxy) resource;
        dataSourceCache.put(dataSourceProxy.getResourceId(), dataSourceProxy);
        super.registerResource(dataSourceProxy);
    }

    // 根据resourceId获取数据库的DataSource
    public DataSourceProxy get(String resourceId) {
        return (DataSourceProxy) dataSourceCache.get(resourceId);
    }

    // 提交成功,调用asyncWorker提交成功
    public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
        return asyncWorker.branchCommit(branchType, xid, branchId, resourceId, applicationData);
    }

    // 事务回滚
    public BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
        DataSourceProxy dataSourceProxy = get(resourceId);
        if (dataSourceProxy == null) {
            throw new ShouldNeverHappenException();
        }
        try {
	    // 委派给UndoLogManager回滚已经提交的数据,将当前resouce的dataSourceProxy传入参数
            UndoLogManager.undo(dataSourceProxy, xid, branchId);
        } catch (TransactionException te) {
            if (LOGGER.isInfoEnabled()){
                LOGGER.info("branchRollback failed reason [{}]", te.getMessage());
            }
            if (te.getCode() == TransactionExceptionCode.BranchRollbackFailed_Unretriable) {
                return BranchStatus.PhaseTwo_RollbackFailed_Unretryable;
            } else {
                return BranchStatus.PhaseTwo_RollbackFailed_Retryable;
            }
        }
        return BranchStatus.PhaseTwo_Rollbacked;

    }
    @Override
    public Map getManagedResources() {
        return dataSourceCache;
    }

    // 此为AT自动模式管理器
    public BranchType getBranchType() {
        return BranchType.AT;
    }
}

六、AsyncWorker

DataSourceManager事务提交委派给AsyncWorker进行提交的。因为都成功了,无需回滚成功的数据,只需要删除生成的
操作日志就行,采用异步方式,提高效率。

public class AsyncWorker implements ResourceManagerInbound {


    private static ScheduledExecutorService timerExecutor;

    @Override
    public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId,
                                     String applicationData) throws TransactionException {
        if (!ASYNC_COMMIT_BUFFER.offer(new Phase2Context(branchType, xid, branchId, resourceId, applicationData))) {
            LOGGER.warn("Async commit buffer is FULL. Rejected branch [" + branchId + "/" + xid
                + "] will be handled by housekeeping later.");
        }
        return BranchStatus.PhaseTwo_Committed;
    }

    // 初始化
    public synchronized void init() {
        LOGGER.info("Async Commit Buffer Limit: " + ASYNC_COMMIT_BUFFER_LIMIT);
	// 创建定时器,每一秒定时doBranchCommits
        timerExecutor = new ScheduledThreadPoolExecutor(1,
            new NamedThreadFactory("AsyncWorker", 1, true));
        timerExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    doBranchCommits();
                } catch (Throwable e) {
                    LOGGER.info("Failed at async committing ... " + e.getMessage());

                }
            }
        }, 10, 1000 * 1, TimeUnit.MILLISECONDS);
    }

    // 分支提交具体方法
    private void doBranchCommits() {
        if (ASYNC_COMMIT_BUFFER.size() == 0) {
            return;
        }
	// 获取需要2步执行的数据Phase2Context,并根据ResourceId进行分类
        Map> mappedContexts = new HashMap<>(DEFAULT_RESOURCE_SIZE);
        while (!ASYNC_COMMIT_BUFFER.isEmpty()) {
            Phase2Context commitContext = ASYNC_COMMIT_BUFFER.poll();
            List contextsGroupedByResourceId = mappedContexts.get(commitContext.resourceId);
            if (contextsGroupedByResourceId == null) {
                contextsGroupedByResourceId = new ArrayList<>();
                mappedContexts.put(commitContext.resourceId, contextsGroupedByResourceId);
            }
            contextsGroupedByResourceId.add(commitContext);
        }

        // 遍历Map.Entry>
        for (Map.Entry> entry : mappedContexts.entrySet()) {
            Connection conn = null;
            try {
                try {
		    // 获取DataSourceManager
                    DataSourceManager resourceManager = (DataSourceManager)DefaultResourceManager.get()
                        .getResourceManager(BranchType.AT);
		    // 更加resourceId获取DataSourceProxy
                    DataSourceProxy dataSourceProxy = resourceManager.get(entry.getKey());
                    if (dataSourceProxy == null) {
                        throw new ShouldNeverHappenException("Failed to find resource on " + entry.getKey());
                    }
		    // 创建连接
                    conn = dataSourceProxy.getPlainConnection();
                } catch (SQLException sqle) {
                    LOGGER.warn("Failed to get connection for async committing on " + entry.getKey(), sqle);
                    continue;
                }
		// 将缓存中的xid和branchId放入数组set中
                List contextsGroupedByResourceId = entry.getValue();
                Set xids = new LinkedHashSet<>(UNDOLOG_DELETE_LIMIT_SIZE);
                Set branchIds = new LinkedHashSet<>(UNDOLOG_DELETE_LIMIT_SIZE);
		// 获取当前resourceId下需要执行的commitContext
                for (Phase2Context commitContext : contextsGroupedByResourceId) {
                    xids.add(commitContext.xid);
                    branchIds.add(commitContext.branchId);
                    int maxSize = xids.size() > branchIds.size() ? xids.size() : branchIds.size();
		    // 如果xid或branchId数组set中有一个等于批量操作1000条,就调用批量删除
                    if (maxSize == UNDOLOG_DELETE_LIMIT_SIZE) {
                        try {
			    // 调用UndoLogManager删除日志
                            UndoLogManager.batchDeleteUndoLog(xids, branchIds, conn);
                        } catch (Exception ex) {
                            LOGGER.warn("Failed to batch delete undo log [" + branchIds + "/" + xids + "]", ex);
                        }
                        xids.clear();
                        branchIds.clear();
                    }
                }

                if (CollectionUtils.isEmpty(xids) || CollectionUtils.isEmpty(branchIds)) {
                    return;
                }
                // 批量删除最后不满1000的数据
                try {
                    UndoLogManager.batchDeleteUndoLog(xids, branchIds, conn);
                } catch (Exception ex) {
                    LOGGER.warn("Failed to batch delete undo log [" + branchIds + "/" + xids + "]", ex);
                }

            } finally {
                if (conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException closeEx) {
                        LOGGER.warn("Failed to close JDBC resource while deleting undo_log ", closeEx);
                    }
                }
            }
        }
    }

    // 不支持回滚
    public BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId,
                                       String applicationData) throws TransactionException {
        throw new NotSupportYetException();

    }
}

七、UndoLogManager

下面是UndoLogManager批量删除undo_log表中日志的逻辑,创建sql,然后批量设置参数,最后批量执行

 public static void batchDeleteUndoLog(Set xids, Set branchIds, Connection conn) throws SQLException {
        int xidSize = xids.size();
        int branchIdSize = branchIds.size();
        String batchDeleteSql = toBatchDeleteUndoLogSql(xidSize, branchIdSize);
        PreparedStatement deletePST = null;
        try {
            deletePST = conn.prepareStatement(batchDeleteSql);
            int paramsIndex = 1;
            for (Long branchId : branchIds) {
                deletePST.setLong(paramsIndex++, branchId);
            }
            for (String xid : xids) {
                deletePST.setString(paramsIndex++, xid);
            }
            int deleteRows = deletePST.executeUpdate();
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("batch delete undo log size " + deleteRows);
            }
        } catch (Exception e) {
            if (!(e instanceof SQLException)) {
                e = new SQLException(e);
            }
            throw (SQLException)e;
        } finally {
            if (deletePST != null) {
                deletePST.close();
            }
        }

    }

下面是UndoLogManager回滚数据执行undo的逻辑

    public static void undo(DataSourceProxy dataSourceProxy, String xid, long branchId) throws TransactionException {
        assertDbSupport(dataSourceProxy.getDbType());
        Connection conn = null;
        ResultSet rs = null;
        PreparedStatement selectPST = null;

        for (; ; ) {
            try {
	        //创建连接
                conn = dataSourceProxy.getPlainConnection();
                // The entire undo process should run in a local transaction.
		//设置为自动提交
                conn.setAutoCommit(false);
                // Find UNDO LOG
                selectPST = conn.prepareStatement(SELECT_UNDO_LOG_SQL);
                selectPST.setLong(1, branchId);
                selectPST.setString(2, xid);
		// 执行查询,找到对应branchId和xid的数据
                rs = selectPST.executeQuery();

                boolean exists = false;
                while (rs.next()) {
                    exists = true;
		    // 获取log_status,保证幂等性,只有正常状态的才能执行
                    int state = rs.getInt("log_status");
                    if (!canUndo(state)) {
                        if (LOGGER.isInfoEnabled()) {
                            LOGGER.info("xid {} branch {}, ignore {} undo_log",
                                xid, branchId, state);
                        }
                        return;
                    }

                    // 获取context
                    String contextString = rs.getString("context");
                    Map context = parseContext(contextString);
		    // 获取rollback_info
                    Blob b = rs.getBlob("rollback_info");
                    byte[] rollbackInfo = BlobUtils.blob2Bytes(b);

                     // 对rollbackInfo数据进行反序列化操作
                    String serializer = context == null ? null : context.get(UndoLogConstants.SERIALIZER_KEY);
                    UndoLogParser parser = serializer == null ? UndoLogParserFactory.getInstance() :
                        UndoLogParserFactory.getInstance(serializer);
                    BranchUndoLog branchUndoLog = parser.decode(rollbackInfo);

                    try {
                        // put serializer name to local
                        SERIALIZER_LOCAL.set(parser.getName());
                        // 循环调用创建sql执行
                        for (SQLUndoLog sqlUndoLog : branchUndoLog.getSqlUndoLogs()) {
                            TableMeta tableMeta = TableMetaCache.getTableMeta(dataSourceProxy, sqlUndoLog.getTableName());
                            sqlUndoLog.setTableMeta(tableMeta);
                            AbstractUndoExecutor undoExecutor = UndoExecutorFactory.getUndoExecutor(
                                    dataSourceProxy.getDbType(),
                                    sqlUndoLog);
                            undoExecutor.executeOn(conn);
                        }
                    } finally {
                        // remove serializer name
                        SERIALIZER_LOCAL.remove();
                    }
                }
		//如果undo_log存在,则意味着分支事务已经完成了第一阶段,我们可以直接回滚并清除undo_log日志。
		//否则,表示分支事务中存在异常,导致无法将撤消日志写入数据库。
		// 例如,业务处理超时,全局事务被发起方回滚。
		// 为了保证数据的一致性,我们可以插入一个具有GlobalFinished状态undo_log日志,以防止其他程序第一阶段的本地事务被正确提交。

                if (exists) {
		   // 存在,已经回滚日志了,进行删除
                    deleteUndoLog(xid, branchId, conn);
                    conn.commit();
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("xid {} branch {}, undo_log deleted with {}",
                            xid, branchId, State.GlobalFinished.name());
                    }
                } else {
		    // 不存在undo_log日志则插入全球状态完成的日志
                    insertUndoLogWithGlobalFinished(xid, branchId, UndoLogParserFactory.getInstance(), conn);
                    conn.commit();
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("xid {} branch {}, undo_log added with {}",
                            xid, branchId, State.GlobalFinished.name());
                    }
                }

                return;
            } catch (SQLIntegrityConstraintViolationException e) {
                // Possible undo_log has been inserted into the database by other processes, retrying rollback undo_log
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("xid {} branch {}, undo_log inserted, retry rollback",
                        xid, branchId);
                }
            } catch (Throwable e) {
                if (conn != null) {
                    try {
                        conn.rollback();
                    } catch (SQLException rollbackEx) {
                        LOGGER.warn("Failed to close JDBC resource while undo ... ", rollbackEx);
                    }
                }
                throw new TransactionException(BranchRollbackFailed_Retriable, String.format("%s/%s", branchId, xid),
                    e);

            } finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (selectPST != null) {
                        selectPST.close();
                    }
                    if (conn != null) {
                        conn.close();
                    }
                } catch (SQLException closeEx) {
                    LOGGER.warn("Failed to close JDBC resource while undo ... ", closeEx);
                }
            }
        }
    }

 

你可能感兴趣的:(seata)