美文网首页程序员Ovirt
【Ovirt 笔记】事务相关实现分析与整理

【Ovirt 笔记】事务相关实现分析与整理

作者: 58bc06151329 | 来源:发表于2018-11-30 17:49 被阅读2次

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

分析整理的版本为 Ovirt 4.2.3 版本。

1. Ovirt 中的事务管理

  • engine 中的 事务管理 是交由 JBoss 容器来完成的,由 JBoss 容器基于 JTA 实现。
    • JNDI 命名目录为 java:jboss/TransactionManager
    • TransactionManagerProducer 类中通过 Java CDITransactionManager 的实现类注入到程序中。
@Produces
@Singleton
public TransactionManager getTransactionManager() throws NamingException {
    return (TransactionManager) new InitialContext().lookup("java:jboss/TransactionManager");
}

1.1 事务传播行为

  • engine 中只定义了三种传播行为,在 TransactionScopeOption 枚举类中进行了定义。
传播行为 说明
Required 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
Suppress 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
RequiresNew 创建新事务,无论当前存不存在事务,都创建新事务。

1.2 事务的支持

  • engine 中定义了 TransactionSupport 工具类,用于事务的支持。
静态方法 说明
findTransactionManager 获取事务管理器(单例对象,存在于 CDI 中)。
suspend 挂起当前线程关联的事务。
resume 继续当前线程关联的事务。
current 返回关联到当前线程的事务。
registerRollbackHandler 回调接口,以便在事务完成时得到通知从而触发一些处理工作,如清除缓存等。可以通过此接口将回调程序注入到事务中,当事务成功提交后,回调程序将被激活。
needToRollback 根据事务状态判断是否需要回滚。
executeInScope 执行事务(根据不同的传播行为)。
executeInNewTransaction 执行传播行为为 RequiresNew 的事务。
setRollbackOnly 标记当前事务将回滚。

1.3 执行事务

执行事务流程
  • 其中深蓝色箭头连线表示公共执行。
  • 橘黄色箭头连线表示 RequiresNew 执行。
  • 绿色箭头连线表示 Required 执行。
  • 浅蓝色箭头连线表示 Suppress 执行。
public static <T> T executeInScope(TransactionScopeOption scope, TransactionMethod<T> code) {
        // check if we are already in rollback
        TransactionManager tm;
        try {
            tm = findTransactionManager();
            if (needToRollback(tm.getStatus())) {
                throw new TransactionRolledbackLocalException(
                        "Current transaction is marked for rollback, no further operations are possible or desired");
            }
        } catch (SystemException e) {
            throw new RuntimeException("Failed to check transaction status - this shouldn't ever happen");
        }
        switch (scope) {
        case RequiresNew:
            return executeInNewTransaction(code);
        case Suppress:
            return executeInSuppressed(tm, code);
        case Required:
            return executeInRequired(tm, code);
        default:
            throw new RuntimeException("Undefined Scope: " + scope);
        }
}

1.3.1 excute 方法

protected final void execute() {
        setCommandStatus(CommandStatus.ACTIVE);
        getReturnValue().setValid(true);
        getReturnValue().setIsSynchronous(true);

        if (shouldPersistCommand()) {
            persistCommandIfNeeded();
            commandCoordinatorUtil.persistCommandAssociatedEntities(getCommandId(), getSubjectEntities());
        }

        executionHandler.addStep(getExecutionContext(), StepEnum.EXECUTING, null);

        handleCommandStepAndEntities();

        try {
            handleTransactivity();
            TransactionSupport.executeInScope(scope, this);
        } catch (TransactionRolledbackLocalException e) {
            log.info("Transaction was aborted in '{}'", this.getClass().getName());
            // Transaction was aborted - we must sure we compensation for all previous applicative stages of the command
            compensate();
        } finally {
            try {
                if (getCommandShouldBeLogged()) {
                    logCommand();
                }
                if (getSucceeded()) {
                    if (getCommandShouldBeLogged()) {
                        logRenamedEntity();
                    }
                    // only after creating all tasks, we can start polling them (we
                    // don't want
                    // to start polling before all tasks were created, otherwise we
                    // might change
                    // the VM/VmTemplate status to 'Down'/'OK' too soon.
                    startPollingAsyncTasks();
                }
            } finally {
                if (noAsyncOperations() && !executionHandler.checkIfJobHasTasks(getExecutionContext())) {
                    executionHandler.endJob(getExecutionContext(), getSucceeded());
                }
            }
        }
}
  • handleTransactivity 通过该方法来设置传播行为。
步骤 说明
第一步 通过 Command 的参数设置该传播行为。
第二步 根据 Command 是否设置了 @NonTransactiveCommandAttribute,决定是否采用 Suppress 传播行为。
第三步 设置了 @NonTransactiveCommandAttribute,同时又设置了 forceCompensation 属性为 true,最终执行第一步的传播行为。
  • executeInScope 执行过程抛出异常,则会执行补偿机制
    • 可以通过 Command 参数中的 shouldbelogged 属性设置是否在执行完成 excuete 后打印日志。
    • 也可以在 Command 过程中通过 setCommandShouldBeLogged 方法设置。
    • excuete 执行成功后,开始跟轮询踪异步任务。

1.3.2 endAction 方法

  • handleCommandExecutionEnded 判断是否需要执行 endAction。
    • 所有的 Command 命令默认执行 endAction。
    • 但是如果该 Command 中包含父 Command 参数,则判断该 Command 的结束程序的属性(Command 参数中可以设置(默认为 PARENT_MANAGED 不自动执行 endAction))是否为 FLOW_MANAGED 或 COMMAND_MANAGED,如果是则执行,否则不执行。
private boolean handleCommandExecutionEnded() {
        boolean shouldEndAction = parentHasCallback() ? isEndProcedureApplicableToEndAction() : true;

        CommandStatus newStatus = isEndSuccessfully() ? CommandStatus.SUCCEEDED : CommandStatus.FAILED;
        if (getCallback() == null) {
            setCommandStatus(newStatus);

            if (!shouldEndAction) {
                logEndWillBeExecutedByParent(newStatus);
            }
        }

        return shouldEndAction;
}
  • endAction 与 execute 有类似的流程,同样需要设置传播行为和是否打印日志。

相关文章

网友评论

    本文标题:【Ovirt 笔记】事务相关实现分析与整理

    本文链接:https://www.haomeiwen.com/subject/wqpwqqtx.html