Factory( LocalInterpreterProperties interpreterProperties, StagingArea stagingArea, InterpreterPropsProvider interpreterPropsProvider, int moduleId, ImmutableList<HasValue> inPortsHasValueList, BitSet recomputedInPorts, BitSet requestedOutPorts) { Objects.requireNonNull(interpreterProperties); Objects.requireNonNull(stagingArea); Objects.requireNonNull(interpreterPropsProvider); Objects.requireNonNull(inPortsHasValueList); Objects.requireNonNull(recomputedInPorts); Objects.requireNonNull(requestedOutPorts); this.interpreterProperties = interpreterProperties; this.stagingArea = stagingArea; this.interpreterPropsProvider = interpreterPropsProvider; RuntimeModule untypedModule = stagingArea.getAnnotatedExecutionTrace().getModule(); if (untypedModule instanceof RuntimeProxyModule) { RuntimeProxyModule proxyModule = (RuntimeProxyModule) untypedModule; RuntimeCompositeModuleDeclaration declaration = (RuntimeCompositeModuleDeclaration) proxyModule.getDeclaration(); module = declaration.getTemplate(); } else { module = (RuntimeParentModule) untypedModule; } this.moduleId = moduleId; this.inPortsHasValueList = inPortsHasValueList; this.recomputedInPorts = (BitSet) Objects.requireNonNull(recomputedInPorts).clone(); this.requestedOutPorts = (BitSet) Objects.requireNonNull(requestedOutPorts).clone(); }
/** * Callback for {@link ComputeResumeState} in order to determine whether a dependency-graph node * has a value or not. * * <p>This method is guaranteed to be called during processing of a message this actor received * (in particular, on the same thread). */ private void asynchronousHasValueCheck(ValueNode valueNode) { ExecutionTrace executionTrace = valueNode.getExecutionTrace(); CompletableFuture<Object> messageFuture = stagingArea .exists(executionTrace) .thenApply(exists -> new FinishedStagingAreaOperation(valueNode, exists)); pipeResultToSelf( messageFuture, "checking if staging area contains execution trace '%s'", executionTrace); }
/** * Returns, and if necessary creates, the submodule interpreter actor for the given submodule. * * <p>A submodule interpreter actor is created at most once during the lifetime of the current * actor. If the submodule actor is created, it will be supervised by the current actor. * * <p>This method starts one asynchronous action for each out-port of the submodule that satisfies * {@link #isOutPortNeeded(RuntimeOutPort)}; these will be finished in {@link * #submoduleOutPortNoLongerNeeded}. This prevents this actor from terminating even though a child * interpreter may still send values for out-ports. * * <p>One additional asynchronous action is started for the child actor, which will be finished in * {@link #childActorTerminated(ActorRef)}. * * @param submodule submodule * @return reference to the submodule actor */ private ActorRef getChildExecutor(RuntimeModule submodule) { assert state == State.REPLAY || state == State.RUNNING || state == State.ALL_OUTPUTS; int submoduleId = submodule.getIndex(); if (childExecutors[submoduleId] == null) { List<SubmoduleInPortNode> submoduleInPortNodes = dependencyGraph.submodulesInPortNodes().get(submoduleId); ImmutableList<HasValue> submoduleInPortHasValueList = submoduleInPortNodes .stream() .map(SubmoduleInPortNode::getHasValue) .collect(ImmutableList.collector()); BitSet submoduleRecomputedInPorts = new BitSet(submodule.getInPorts().size()); submoduleInPortNodes .stream() .filter(node -> node.getPortState() == PortState.RECOMPUTE) .forEach(node -> submoduleRecomputedInPorts.set(node.getElement().getInIndex())); BitSet submoduleRequestedOutPorts = computeResumeState.getSubmodulesNeededOutPorts()[submoduleId]; submoduleRequestedOutPorts .stream() .mapToObj(id -> submodule.getOutPorts().get(id)) .forEach( outPort -> startAsynchronousAction( outPort, "waiting for value to pass through submodule out-port %s#%s", submodule.getSimpleName(), outPort.getSimpleName())); childExecutors[submoduleId] = getContext() .actorOf( interpreterPropsProvider.provideInterpreterProps( getInterpreterProperties(), stagingArea.resolveDescendant( ExecutionTrace.empty() .resolveContent() .resolveModule(submodule.getSimpleName())), submoduleId, submoduleInPortHasValueList, submoduleRecomputedInPorts, submoduleRequestedOutPorts), submodule.getSimpleName().toString()); getContext().watch(childExecutors[submoduleId]); childActorMap.put(childExecutors[submoduleId], submodule); startAsynchronousAction( childExecutors[submoduleId], "supervising interpreter for submodule %s", submodule.getSimpleName()); } return childExecutors[submoduleId]; }
/** * Handles event that the value of a submodule's out-port is no longer needed. * * <p>If the submodule of the given out-port no longer has any (other) out-port whose value is * required, this method starts (asynchronously) cleaning all intermediate results for this * module. * * <p>This method also finishes the asynchronous action (waiting for submodule out-port) started * previously in {@link #getChildExecutor}. * * @param outPort out-port whose value is no longer needed */ private void submoduleOutPortNoLongerNeeded(RuntimeOutPort outPort) { assert state.compareTo(State.RUNNING) >= 0; RuntimeModule submodule = outPort.getModule(); BitSet neededOutPorts = computeResumeState.getSubmodulesNeededOutPorts()[submodule.getIndex()]; neededOutPorts.set(outPort.getOutIndex(), false); if (neededOutPorts.isEmpty() && getInterpreterProperties().isCleaningRequested()) { ExecutionTrace executionTrace = ExecutionTrace.empty().resolveContent().resolveModule(submodule.getSimpleName()); CompletableFuture<Void> future = stagingArea.delete(executionTrace); awaitAsynchronousAction( future, "cleaning up intermediate output of submodule '%s'", submodule.getSimpleName()); } endAsynchronousAction(outPort); }