StreamTask异步执行Checkpoint操作

文章详细阐述了ApacheFlink的StreamTask在执行Checkpoint操作时的流程,包括异步非阻塞的实现方式,如何将状态快照操作封装成OperatorSnapshotFutures,定义工作线程Runnable并在线程池中执行快照持久化操作,以及涉及的关键类和方法的作用。整个过程确保了数据处理的连续性并保证状态一致性。
摘要由CSDN通过智能技术生成


不管是CheckpointCoordinator触发Source节点引起的Checkpoint,还是Barrier对齐引起的Checkpoint,最终都得将“异步非阻塞的执行Checkpoint”的操作交给StreamTask,在线程池中执行。

/**
 * 开始执行Task实例的Checkpoint操作
 * 该方法的触发方式有2种:
 *		1.CheckpointCoordinator组件周期性的触发Source节点的Checkpoint操作
 *		2.下游算子通过CheckpointBarrier对齐触发本节点算子的Checkpoint操作
 * 不管哪种触发,最终都得调用该方法完成状态数据的持久化
 * 注意:会先将Barrier广播给下游算子,然后本Task才会做自己的Checkpoint。如此循环...
 */
private boolean performCheckpoint(
    CheckpointMetaData checkpointMetaData,
    CheckpointOptions checkpointOptions,
    CheckpointMetrics checkpointMetrics,
    boolean advanceToEndOfTime) throws Exception {

    LOG.debug("Starting checkpoint ({}) {} on task {}",
              checkpointMetaData.getCheckpointId(), checkpointOptions.getCheckpointType(), getName());

    final long checkpointId = checkpointMetaData.getCheckpointId();

    // 判断当前Task是否正常运行
    if (isRunning) {
        // 核心:使用线程池以异步非阻塞的方式执行Checkpoint操作(不会block数据的正常处理)
        actionExecutor.runThrowing(() -> {

            if (checkpointOptions.getCheckpointType().isSynchronous()) {
                setSynchronousSavepointId(checkpointId);

                if (advanceToEndOfTime) {
                    advanceToEndOfEventTime();
                }
            }

            /**
			 * step 1:让OperatorChain中的所有Operator执行“pre-barrier”
			 */
            operatorChain.prepareSnapshotPreBarrier(checkpointId);

            /**
			 * stpe 2:先将CheckpointBarrier事件广播到下游的节点中
			 * 		   广播本质:在Task的输出ResultPartition中,会给下游所有的Channel都发送一个CheckpointBarrier事件
			 */
            operatorChain.broadcastCheckpointBarrier(
                checkpointId,
                checkpointMetaData.getTimestamp(),
                checkpointOptions);

            /**
			 * step 3(核心):对StreamTask中的OperatorChain内的所有StreamOperator,异步执行“状态数据快照”操作(异步非阻塞,不影响数据的正常处理)
			 */
            checkpointState(checkpointMetaData, checkpointOptions, checkpointMetrics);

        });

        return true;
    } else {
        /**
		 * 如果isRunning为false,表示Task不在运行状态。这种状态下,需要将“CancelCheckpointMarker消息”发送给OperatorChain中所有的StreamOperator,
		 * 并向下游算子进行广播。当且仅当OperatorChain中的算子还没执行完Checkpoint操作时,下游算子收到“CancelCheckpointMarker消息”后,才会立即取消Checkpoint操作。
		 */
        actionExecutor.runThrowing(() -> {
            final CancelCheckpointMarker message = new CancelCheckpointMarker(checkpointMetaData.getCheckpointId());
            // 将“CancelCheckpointMarker消息”广播给其他算子
            recordWriter.broadcastEvent(message);
        });

        return false;
    }
}

StreamTask在执行Checkpoint的过程中,一方面将CheckpointBarrier事件发送给下游的节点,一方面让这个StreamTask内的OperatorChain中的所有的StreamOperator均执行“状态数据快照”操作。当然,如果Task实例并未正常运行,那就将“CancelCheckpointMarker消息”发送给OperatorChain中的所有StreamOperator,并向下游算子进行广播,让它们立即取消Checkpoint操作。

StreamTask会对OperatorChain内的所有StreamOperator,异步执行“状态数据快照”操作。由于CheckpointingOperation实例封装了Checkpoint执行的具体操作流程,以及执行Checkpoint操作需要用到的环境配置信息,因此“千斤重担”就落在了它身上,由CheckpointingOperation负责“快照操作”的指挥。

/**
 * 对StreamTask中的OperatorChain内的所有StreamOperator,异步执行“状态数据快照”操作
 */
private void checkpointState(
    CheckpointMetaData checkpointMetaData,
    CheckpointOptions checkpointOptions,
    CheckpointMetrics checkpointMetrics) throws Exception {

    // 创建CheckpointStreamFactory实例:就相当于是指向Checkpoint数据的存储位置的指针
    // 以MemCheckpointStreamFactory为例,它会接受不超过指定字节数限制的序列化后的状态
    CheckpointStreamFactory storage = checkpointStorage.resolveCheckpointStorageLocation(
        checkpointMetaData.getCheckpointId(),
        checkpointOptions.getTargetLocation());

    // 创建CheckpointingOperation实例(封装了Checkpoint执行的具体操作流程,以及执行Checkpoint操作需要用到的环境配置信息)
    CheckpointingOperation checkpointingOperation = new CheckpointingOperation(
        this,
        checkpointMetaData,
        checkpointOptions,
        storage,
        checkpointMetrics);

    // 核心:真正地执行Checkpoint操作
    checkpointingOperation.executeCheckpointing();
}

CheckpointintOperation指挥执行Checkpoint,有3个核心步骤:

  • 1.由StreamOperator的子类提供“异步执行状态快照操作”的具体实现逻辑,并将其注册到OperatorSnapshotFutures对象中等待执行,并保存到映射关系为“OperatorId:OperatorSnapshotFutures对象”的Map集合中
  • 2.定义工作线程Runnable,并持有“保存有众多OperatorSnapshotFutures”的Map集合
  • 3.由线程池异步执行Runnable中的众多“快照持久化操作”,不会影响数据流的正常处理
/**
 * 真正地执行Checkpoint操作
 * 核心逻辑:OperatorSnapshotFutures表示为“状态快照持久化操作”,将其保存到Map集合中
 */
public void executeCheckpointing() throws Exception {
    startSyncPartNano = System.nanoTime();

    try {
        // 遍历所有的StreamOperator算子
        for (StreamOperator<?> op : allOperators) {
            /**
			 * 定义每个StreamOperator的“异步执行状态快照”操作,并将其注册给OperatorSnapshotFutures对象等待执行,
			 * 按照“OperatorId:OperatorSnapshotFutures对象”的映射关系,保存到Map中。
			 * 下面会由线程池中的Runnable任务来异步执行这些“操作”
			 */
            checkpointStreamOperator(op);
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Finished synchronous checkpoints for checkpoint {} on task {}",
                      checkpointMetaData.getCheckpointId(), owner.getName());
        }

        startAsyncPartNano = System.nanoTime();

        checkpointMetrics.setSyncDurationMillis((startAsyncPartNano - startSyncPartNano) / 1_000_000);

        // 创建Runnable任务:内含“装有每个StreamOperator的执行状态快照操作”所对应的Map集合
        AsyncCheckpointRunnable asyncCheckpointRunnable = new AsyncCheckpointRunnable(
            owner,
            operatorSnapshotsInProgress, // 存放了所有Operator的“状态快照”的结果--OperatorSnapshotFutures对象
            checkpointMetaData,
            checkpointMetrics,
            startAsyncPartNano);

        owner.cancelables.registerCloseable(asyncCheckpointRunnable);
        // 使用StreamTask内的ExecutorService(异步快照工作线程池),执行这个Runnable任务(容纳了每个StreamOperator的“快照持久化”的操作)
        // 目的:不影响数据流的正常处理
        owner.asyncOperationsThreadPool.execute(asyncCheckpointRunnable);

        if (LOG.isDebugEnabled()) {
            LOG.debug("{} - finished synchronous part of checkpoint {}. " +
                      "Alignment duration: {} ms, snapshot duration {} ms",
                      owner.getName(), checkpointMetaData.getCheckpointId(),
                      checkpointMetrics.getAlignmentDurationNanos() / 1_000_000,
                      checkpointMetrics.getSyncDurationMillis());
        }
    } catch (Exception ex) {
        for (OperatorSnapshotFutures operatorSnapshotResult : operatorSnapshotsInProgress.values()) {
            if (null != operatorSnapshotResult) {
                try {
                    operatorSnapshotResult.cancel();
                } catch (Exception e) {
                    LOG.warn("Could not properly cancel an operator snapshot result.", e);
                }
            }
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("{} - did NOT finish synchronous part of checkpoint {}. " +
                      "Alignment duration: {} ms, snapshot duration {} ms",
                      owner.getName(), checkpointMetaData.getCheckpointId(),
                      checkpointMetrics.getAlignmentDurationNanos() / 1_000_000,
                      checkpointMetrics.getSyncDurationMillis());
        }

        if (checkpointOptions.getCheckpointType().isSynchronous()) {
            throw ex;
        } else {
            owner.getEnvironment().declineCheckpoint(checkpointMetaData.getCheckpointId(), ex);
        }
    }
}

下面就看一下这核心的三板斧,到底是怎么抡的。

1.将状态快照操作,“封印”成OperatorSnapshotFutures

遍历所有的StreamOperator算子,将每个StreamOperator要执行“异步执行状态快照”的操作,注册到OperatorSnapshotFutures中等待执行。

/**
 * 将每个StreamOperator的“异步执行状态快照”的操作,注册给OperatorSnapshotFutures对象等待执行,
 * 按照“OperatorId:OperatorSnapshotFutures对象”的映射关系,保存到Map中。
 */
@SuppressWarnings("deprecation")
private void checkpointStreamOperator(StreamOperator<?> op) throws Exception {
    if (null != op) {

        // 这里会调用StreamOperator#snapshotState()方法,将当前StreamOperator的状态快照操作,“封印”到OperatorSnapshotFutures对象中
        // tips:如果对Checkpoint过程由特殊逻辑要求,可以在StreamOperator的实现子类中,通过覆写CheckpointedFunction提供的“钩子”方法来满足
        OperatorSnapshotFutures snapshotInProgress = op.snapshotState(
            checkpointMetaData.getCheckpointId(),
            checkpointMetaData.getTimestamp(),
            checkpointOptions,
            storageLocation);
        // 将象征着“异步快照操作”的OperatorSnapshotFutures对象,保存到Map集合中,下一步会使用异步快照工作线程池ExecutorService,异步地执行算子的异步快照操作
        operatorSnapshotsInProgress.put(op.getOperatorID(), snapshotInProgress);
    }
}

首先是准备好OperatorSnapshotFutures对象,然后准备好执行状态快照需要用到的上下文。接着将“快照持久化操作”注册到OperatorSnapshotFutures中等待执行。本质就是将KeyedStateBackend、OperatorStateBackend的“快照持久化操作”set到OperatorSnapshotFutures中,后期线程池执行Runnable任务时会将其取出执行。

/**
 * StreamTask在执行Checkpoint对状态数据进行snapshot时,如果对Checkpoint过程有特殊逻辑要求,可以在StreamOperator的子类中通过覆写CheckpointedFunction接口定义的钩子方法实现。
 * 然后KeyedStateBackend、OperatorStateBackend的“快照持久化操作”会被set到OperatorSnapshotFutures中等待执行。
 * 然后会按照“OperatorId:OperatorSnapshotFutures”的映射关系,存到Map集合中。Map集合会被添加到Runnable任务的执行逻辑中。
 * 后面会有一个专门的异步快照工作线程池--ExecutorService,执行这个Runnable任务
 */
@Override
public final OperatorSnapshotFutures snapshotState(long checkpointId, long timestamp, CheckpointOptions checkpointOptions,
                                                   CheckpointStreamFactory factory) throws Exception {

    // KeyGroupRange是状态后端在对键控状态处理时,划定key的索引范围的。
    // 如果keyedStateBackend不为null,就直接获取KeyGroupRange。否则,就new一个KeyGroupRange出来
    KeyGroupRange keyGroupRange = null != keyedStateBackend ?
        keyedStateBackend.getKeyGroupRange() : KeyGroupRange.EMPTY_KEY_GROUP_RANGE;

    // 创建OperatorSnapshotFutures对象
    OperatorSnapshotFutures snapshotInProgress = new OperatorSnapshotFutures();

    // StateSnapshotContextSynchronousImpl用来存储“执行快照”的过程中需要用到的上下文信息
    StateSnapshotContextSynchronousImpl snapshotContext = new StateSnapshotContextSynchronousImpl(
        checkpointId,
        timestamp,
        factory,
        keyGroupRange,
        getContainingTask().getCancelables());

    try {
        // CheckpointedFunction定义了可以覆写的“钩子”方法,在StreamOperator的子类中(通过自定义Function)可以为其提供具体的实现逻辑,
		// 以满足Checkpoint时的特殊逻辑要求,例如:删除状态中的某些数据、添加一些特殊数据等。
        snapshotState(snapshotContext);

        // 包装OperatorSnapshotFutures对象:指定专门用于处理原生状态数据的快照操作
        snapshotInProgress.setKeyedStateRawFuture(snapshotContext.getKeyedStateStreamFuture());
        snapshotInProgress.setOperatorStateRawFuture(snapshotContext.getOperatorStateStreamFuture());

        // 把OperatorStateBackend的“快照持久化”操作包装到OperatorSnapshotFutures中,等待执行
        if (null != operatorStateBackend) {
            snapshotInProgress.setOperatorStateManagedFuture(
                operatorStateBackend.snapshot(checkpointId, timestamp, factory, checkpointOptions));
        }

        // 把KeyedStateBackend的“快照持久化”操作包装到OperatorSnapshotFutures中,等待执行
        if (null != keyedStateBackend) {
            snapshotInProgress.setKeyedStateManagedFuture(
                keyedStateBackend.snapshot(checkpointId, timestamp, factory, checkpointOptions));
        }
    } catch (Exception snapshotException) {
        try {
            snapshotInProgress.cancel();
        } catch (Exception e) {
            snapshotException.addSuppressed(e);
        }

        String snapshotFailMessage = "Could not complete snapshot " + checkpointId + " for operator " +
            getOperatorName() + ".";

        if (!getContainingTask().isCanceled()) {
            LOG.info(snapshotFailMessage, snapshotException);
        }
        try {
            snapshotContext.closeExceptionally();
        } catch (IOException e) {
            snapshotException.addSuppressed(e);
        }
        // 一旦上面做snapshot的过程中出现异常,就会往上层抛。TaskManager接到异常后,会取消所有Task任务并启动Job重启策略
        throw new CheckpointException(snapshotFailMessage, CheckpointFailureReason.CHECKPOINT_DECLINED, snapshotException);
    }

    // 此时,经过包装的OperatorSnapshotFutures对象,拥有一堆的RunnableFuture(等待执行的异步任务)
    return snapshotInProgress;
}

需要注意的是:如果对Checkpoint过程有特殊逻辑要求,可以在StreamOperator的子类中通过覆写CheckpointedFunction接口定义的钩子方法实现。

最后,每个StreamOperator对应的OperatorSnapshotFutures对象包装完成后,就会被保存到映射关系为:“OperatorId:OperatorSnapshotFutures对象”的Map集合中

2.定义工作线程Runnable

AsyncCheckpointRunnable负责执行“快照持久化操作”,容纳所有的OperatorSnapshotFutures对象的Map集合都已经被保存到这个Runnable中了。

// 创建Runnable任务:内含“装有每个StreamOperator的执行状态快照操作”所对应的Map集合
AsyncCheckpointRunnable asyncCheckpointRunnable = new AsyncCheckpointRunnable(
    owner,
    operatorSnapshotsInProgress, // 存放了所有Operator的“状态快照”的结果--OperatorSnapshotFutures对象
    checkpointMetaData,
    checkpointMetrics,
    startAsyncPartNano);


/**
 * 负责执行“快照持久化操作”的Runnable任务
 */
AsyncCheckpointRunnable(
    StreamTask<?, ?> owner,
    Map<OperatorID, OperatorSnapshotFutures> operatorSnapshotsInProgress,
    CheckpointMetaData checkpointMetaData,
    CheckpointMetrics checkpointMetrics,
    long asyncStartNanos) {

    this.owner = Preconditions.checkNotNull(owner);
    this.operatorSnapshotsInProgress = Preconditions.checkNotNull(operatorSnapshotsInProgress);
    this.checkpointMetaData = Preconditions.checkNotNull(checkpointMetaData);
    this.checkpointMetrics = Preconditions.checkNotNull(checkpointMetrics);
    this.asyncStartNanos = asyncStartNanos;
}

3.在线程池中执行Runnable中的“快照持久化操作”

当Runnable任务被执行时,就会调用它的run()方法。本质就是将Runnable任务中的OperatorSnapshotFutures保存的“快照持久化操作”取出来执行

/**
 * 遍历每个StreamOperator对应的OperatorSnapshotFutures,并执行“快照持久化操作”
 */
@Override
public void run() {
    // 为当前线程初始化“文件系统安全网”,确保数据能够正常写入
    FileSystemSafetyNet.initializeSafetyNetForThread();
    try {

        // 存储和记录发送给JobManager的Checkpoint数据
        TaskStateSnapshot jobManagerTaskOperatorSubtaskStates =
            new TaskStateSnapshot(operatorSnapshotsInProgress.size());

        // 存储TaskExecutor本地的状态数据
        TaskStateSnapshot localTaskOperatorSubtaskStates =
            new TaskStateSnapshot(operatorSnapshotsInProgress.size());

        // 遍历每个OperatorSnapshotFutures
        for (Map.Entry<OperatorID, OperatorSnapshotFutures> entry : operatorSnapshotsInProgress.entrySet()) {

            // key:算子id
            OperatorID operatorID = entry.getKey();
            // value:算子对应的状态快照持久化操作
            OperatorSnapshotFutures snapshotInProgress = entry.getValue();

            // finalize the async part of all by executing all snapshot runnables
            // OperatorSnapshotFinalizer会被用来(在构造方法中)执行所有算子的(算子状态、键控状态的)“快照持久化操作”
            OperatorSnapshotFinalizer finalizedSnapshots =
                new OperatorSnapshotFinalizer(snapshotInProgress);

            // 从OperatorSnapshotFinalizer中取出(执行完快照持久化操作后的)JobManager和TaskExecutor的Checkpoint数据,并分别存储起来
            jobManagerTaskOperatorSubtaskStates.putSubtaskStateByOperatorID(
                operatorID,
                finalizedSnapshots.getJobManagerOwnedState());

            localTaskOperatorSubtaskStates.putSubtaskStateByOperatorID(
                operatorID,
                finalizedSnapshots.getTaskLocalState());
        }

        final long asyncEndNanos = System.nanoTime();
        final long asyncDurationMillis = (asyncEndNanos - asyncStartNanos) / 1_000_000L;

        // CheckpointMetrics会记录Checkpoint的执行时间,并汇总到监控系统中
        checkpointMetrics.setAsyncDurationMillis(asyncDurationMillis);

        // 如果AsyncCheckpointState的状态为COMPLETED,就向JobManager汇报Checkpoint的执行结果
        if (asyncCheckpointState.compareAndSet(CheckpointingOperation.AsyncCheckpointState.RUNNING,
                                               CheckpointingOperation.AsyncCheckpointState.COMPLETED)) {

            // 向JobManager汇报Checkpoint的执行结果
            reportCompletedSnapshotStates(
                jobManagerTaskOperatorSubtaskStates,
                localTaskOperatorSubtaskStates,
                asyncDurationMillis);

        } else {
            LOG.debug("{} - asynchronous part of checkpoint {} could not be completed because it was closed before.",
                      owner.getName(),
                      checkpointMetaData.getCheckpointId());
        }
    } catch (Exception e) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("{} - asynchronous part of checkpoint {} could not be completed.",
                      owner.getName(),
                      checkpointMetaData.getCheckpointId(),
                      e);
        }
        // 处理异常情况
        handleExecutionException(e);
    } finally {
        owner.cancelables.unregisterCloseable(this);
        FileSystemSafetyNet.closeSafetyNetAndGuardedResourcesForThread();
    }
}

OperatorSnapshotFinalizer会被用来(在构造方法中)执行所有算子所对应的(算子状态、键控状态的)“快照持久化操作”。执行完毕后,会向JobManager汇报Checkpoint的执行结果。

public OperatorSnapshotFinalizer(
    @Nonnull OperatorSnapshotFutures snapshotFutures) throws ExecutionException, InterruptedException {

    // 执行KeyedState的“快照持久化操作”
    SnapshotResult<KeyedStateHandle> keyedManaged =
        FutureUtils.runIfNotDoneAndGet(snapshotFutures.getKeyedStateManagedFuture());

    SnapshotResult<KeyedStateHandle> keyedRaw =
        FutureUtils.runIfNotDoneAndGet(snapshotFutures.getKeyedStateRawFuture());

    // 执行OperatorState的“快照持久化操作”
    SnapshotResult<OperatorStateHandle> operatorManaged =
        FutureUtils.runIfNotDoneAndGet(snapshotFutures.getOperatorStateManagedFuture());

    SnapshotResult<OperatorStateHandle> operatorRaw =
        FutureUtils.runIfNotDoneAndGet(snapshotFutures.getOperatorStateRawFuture());

    // 将Checkpoint数据保存到OperatorSubtaskState中
    jobManagerOwnedState = new OperatorSubtaskState(
        operatorManaged.getJobManagerOwnedSnapshot(),
        operatorRaw.getJobManagerOwnedSnapshot(),
        keyedManaged.getJobManagerOwnedSnapshot(),
        keyedRaw.getJobManagerOwnedSnapshot()
    );

    taskLocalState = new OperatorSubtaskState(
        operatorManaged.getTaskLocalSnapshot(),
        operatorRaw.getTaskLocalSnapshot(),
        keyedManaged.getTaskLocalSnapshot(),
        keyedRaw.getTaskLocalSnapshot()
    );
}

快照持久化操作的执行,依赖于StateBackend。以HeapKeyedStateBackend为例,若想执行快照持久化,SnapshotStrategy接口定义了对状态数据进行“状态快照持久化”的接口方法

/**
 * StreamOperator刚刚已经执行完了状态快照,接下来xxxStateBackend要做的就是基于SnapshotStrategy对状态数据进行“状态快照持久化”。
 * 具体的持久化方式,由SnapshotStrategy接口的实现子类提供具体的实现逻辑。
 * 该方法就是将持久化操作,注册到OperatorSnapshotFutures中等待执行。
 */
@Nonnull
@Override
@SuppressWarnings("unchecked")
public RunnableFuture<SnapshotResult<KeyedStateHandle>> snapshot(
    final long checkpointId,
    final long timestamp,
    @Nonnull final CheckpointStreamFactory streamFactory,
    @Nonnull CheckpointOptions checkpointOptions) throws IOException {

    long startTime = System.currentTimeMillis();

    // SnapshotStrategy接口定义了对状态数据进行“状态快照持久化”的接口方法
    final RunnableFuture<SnapshotResult<KeyedStateHandle>> snapshotRunner =
        snapshotStrategy.snapshot(checkpointId, timestamp, streamFactory, checkpointOptions);

    snapshotStrategy.logSyncCompleted(streamFactory, startTime);
    return snapshotRunner;
}

SnapshotStrategy接口的实现子类为其提供了具体的实现逻辑:

/**
 * HeapSnapshotStrategy对SnapshotStrategy接口提供的“状态快照持久化”接口方法的具体实现逻辑
 */
@Nonnull
@Override
public RunnableFuture<SnapshotResult<KeyedStateHandle>> snapshot(
    long checkpointId,
    long timestamp,
    @Nonnull CheckpointStreamFactory primaryStreamFactory,
    @Nonnull CheckpointOptions checkpointOptions) throws IOException {

    // 省略部分代码...

    // 对KeyedState、OperatorState的状态快照持久化的处理逻辑
    processSnapshotMetaInfoForAllStates(
        metaInfoSnapshots,
        cowStateStableSnapshots,
        stateNamesToId,
        registeredKVStates,
        StateMetaInfoSnapshot.BackendStateType.KEY_VALUE);

    processSnapshotMetaInfoForAllStates(
        metaInfoSnapshots,
        cowStateStableSnapshots,
        stateNamesToId,
        registeredPQStates,
        StateMetaInfoSnapshot.BackendStateType.PRIORITY_QUEUE);

    // 省略部分代码...
}

在HeapSnapshotStrategy中会取出StateSnapshotRestore,来创建对应类型的状态快照

/**
 * 对KeyedState、OperatorState的状态快照持久化的处理逻辑
 */
private void processSnapshotMetaInfoForAllStates(
    List<StateMetaInfoSnapshot> metaInfoSnapshots,
    Map<StateUID, StateSnapshot> cowStateStableSnapshots,
    Map<StateUID, Integer> stateNamesToId,
    Map<String, ? extends StateSnapshotRestore> registeredStates,
    StateMetaInfoSnapshot.BackendStateType stateType) {

    for (Map.Entry<String, ? extends StateSnapshotRestore> kvState : registeredStates.entrySet()) {
        final StateUID stateUid = StateUID.of(kvState.getKey(), stateType);
        stateNamesToId.put(stateUid, stateNamesToId.size());
        // Value值:处理状态快照、状态恢复的接口
        StateSnapshotRestore state = kvState.getValue();
        if (null != state) {
            // 核心:(基于不同的StateSnapshotRestore)创建状态快照
            final StateSnapshot stateSnapshot = state.stateSnapshot();
            // 将状态快照保存到对应集合中,完成堆内存存储类型KvState的快照操作
            metaInfoSnapshots.add(stateSnapshot.getMetaInfoSnapshot());
            cowStateStableSnapshots.put(stateUid, stateSnapshot);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值