public void updateInputChannel(InputChannelDeploymentDescriptor icdd)
      throws IOException, InterruptedException {
    synchronized (requestLock) {
      if (isReleased) {
        // There was a race with a task failure/cancel
        return;
      }

      final IntermediateResultPartitionID partitionId =
          icdd.getConsumedPartitionId().getPartitionId();

      InputChannel current = inputChannels.get(partitionId);

      if (current.getClass() == UnknownInputChannel.class) {

        UnknownInputChannel unknownChannel = (UnknownInputChannel) current;

        InputChannel newChannel;

        ResultPartitionLocation partitionLocation = icdd.getConsumedPartitionLocation();

        if (partitionLocation.isLocal()) {
          newChannel = unknownChannel.toLocalInputChannel();
        } else if (partitionLocation.isRemote()) {
          newChannel = unknownChannel.toRemoteInputChannel(partitionLocation.getConnectionId());
        } else {
          throw new IllegalStateException("Tried to update unknown channel with unknown channel.");
        }

        LOG.debug("Updated unknown input channel to {}.", newChannel);

        inputChannels.put(partitionId, newChannel);

        newChannel.requestSubpartition(consumedSubpartitionIndex);

        for (TaskEvent event : pendingEvents) {
          newChannel.sendTaskEvent(event);
        }

        if (--numberOfUninitializedChannels == 0) {
          pendingEvents.clear();
        }
      }
    }
  }
Example #2
0
  void scheduleOrUpdateConsumers(List<List<ExecutionEdge>> allConsumers) {
    final int numConsumers = allConsumers.size();

    if (numConsumers > 1) {
      fail(
          new IllegalStateException(
              "Currently, only a single consumer group per partition is supported."));
    } else if (numConsumers == 0) {
      return;
    }

    for (ExecutionEdge edge : allConsumers.get(0)) {
      final ExecutionVertex consumerVertex = edge.getTarget();

      final Execution consumer = consumerVertex.getCurrentExecutionAttempt();
      final ExecutionState consumerState = consumer.getState();

      final IntermediateResultPartition partition = edge.getSource();

      // ----------------------------------------------------------------
      // Consumer is created => try to deploy and cache input channel
      // descriptors if there is a deployment race
      // ----------------------------------------------------------------
      if (consumerState == CREATED) {
        final Execution partitionExecution = partition.getProducer().getCurrentExecutionAttempt();

        consumerVertex.cachePartitionInfo(
            PartialInputChannelDeploymentDescriptor.fromEdge(partition, partitionExecution));

        // When deploying a consuming task, its task deployment descriptor will contain all
        // deployment information available at the respective time. It is possible that some
        // of the partitions to be consumed have not been created yet. These are updated
        // runtime via the update messages.
        //
        // TODO The current approach may send many update messages even though the consuming
        // task has already been deployed with all necessary information. We have to check
        // whether this is a problem and fix it, if it is.
        future(
            new Callable<Boolean>() {
              @Override
              public Boolean call() throws Exception {
                try {
                  consumerVertex.scheduleForExecution(
                      consumerVertex.getExecutionGraph().getScheduler(),
                      consumerVertex.getExecutionGraph().isQueuedSchedulingAllowed());
                } catch (Throwable t) {
                  fail(
                      new IllegalStateException(
                          "Could not schedule consumer " + "vertex " + consumerVertex, t));
                }

                return true;
              }
            },
            executionContext);

        // double check to resolve race conditions
        if (consumerVertex.getExecutionState() == RUNNING) {
          consumerVertex.sendPartitionInfos();
        }
      }
      // ----------------------------------------------------------------
      // Consumer is running => send update message now
      // ----------------------------------------------------------------
      else {
        if (consumerState == RUNNING) {
          final SimpleSlot consumerSlot = consumer.getAssignedResource();

          if (consumerSlot == null) {
            // The consumer has been reset concurrently
            continue;
          }

          final Instance consumerInstance = consumerSlot.getInstance();

          final ResultPartitionID partitionId =
              new ResultPartitionID(partition.getPartitionId(), attemptId);

          final Instance partitionInstance =
              partition.getProducer().getCurrentAssignedResource().getInstance();

          final ResultPartitionLocation partitionLocation;

          if (consumerInstance.equals(partitionInstance)) {
            // Consuming task is deployed to the same instance as the partition => local
            partitionLocation = ResultPartitionLocation.createLocal();
          } else {
            // Different instances => remote
            final ConnectionID connectionId =
                new ConnectionID(
                    partitionInstance.getInstanceConnectionInfo(),
                    partition.getIntermediateResult().getConnectionIndex());

            partitionLocation = ResultPartitionLocation.createRemote(connectionId);
          }

          final InputChannelDeploymentDescriptor descriptor =
              new InputChannelDeploymentDescriptor(partitionId, partitionLocation);

          final UpdatePartitionInfo updateTaskMessage =
              new UpdateTaskSinglePartitionInfo(
                  consumer.getAttemptId(), partition.getIntermediateResult().getId(), descriptor);

          sendUpdatePartitionInfoRpcCall(consumerSlot, updateTaskMessage);
        }
        // ----------------------------------------------------------------
        // Consumer is scheduled or deploying => cache input channel
        // deployment descriptors and send update message later
        // ----------------------------------------------------------------
        else if (consumerState == SCHEDULED || consumerState == DEPLOYING) {
          final Execution partitionExecution = partition.getProducer().getCurrentExecutionAttempt();

          consumerVertex.cachePartitionInfo(
              PartialInputChannelDeploymentDescriptor.fromEdge(partition, partitionExecution));

          // double check to resolve race conditions
          if (consumerVertex.getExecutionState() == RUNNING) {
            consumerVertex.sendPartitionInfos();
          }
        }
      }
    }
  }
  /** Creates an input gate and all of its input channels. */
  public static SingleInputGate create(
      String owningTaskName,
      JobID jobId,
      ExecutionAttemptID executionId,
      InputGateDeploymentDescriptor igdd,
      NetworkEnvironment networkEnvironment) {

    final IntermediateDataSetID consumedResultId = checkNotNull(igdd.getConsumedResultId());

    final int consumedSubpartitionIndex = igdd.getConsumedSubpartitionIndex();
    checkArgument(consumedSubpartitionIndex >= 0);

    final InputChannelDeploymentDescriptor[] icdd =
        checkNotNull(igdd.getInputChannelDeploymentDescriptors());

    final SingleInputGate inputGate =
        new SingleInputGate(
            owningTaskName,
            jobId,
            executionId,
            consumedResultId,
            consumedSubpartitionIndex,
            icdd.length,
            networkEnvironment.getPartitionStateChecker());

    // Create the input channels. There is one input channel for each consumed partition.
    final InputChannel[] inputChannels = new InputChannel[icdd.length];

    for (int i = 0; i < inputChannels.length; i++) {

      final ResultPartitionID partitionId = icdd[i].getConsumedPartitionId();
      final ResultPartitionLocation partitionLocation = icdd[i].getConsumedPartitionLocation();

      if (partitionLocation.isLocal()) {
        inputChannels[i] =
            new LocalInputChannel(
                inputGate,
                i,
                partitionId,
                networkEnvironment.getPartitionManager(),
                networkEnvironment.getTaskEventDispatcher(),
                networkEnvironment.getPartitionRequestInitialAndMaxBackoff());
      } else if (partitionLocation.isRemote()) {
        inputChannels[i] =
            new RemoteInputChannel(
                inputGate,
                i,
                partitionId,
                partitionLocation.getConnectionId(),
                networkEnvironment.getConnectionManager(),
                networkEnvironment.getPartitionRequestInitialAndMaxBackoff());
      } else if (partitionLocation.isUnknown()) {
        inputChannels[i] =
            new UnknownInputChannel(
                inputGate,
                i,
                partitionId,
                networkEnvironment.getPartitionManager(),
                networkEnvironment.getTaskEventDispatcher(),
                networkEnvironment.getConnectionManager(),
                networkEnvironment.getPartitionRequestInitialAndMaxBackoff());
      } else {
        throw new IllegalStateException("Unexpected partition location.");
      }

      inputGate.setInputChannel(partitionId.getPartitionId(), inputChannels[i]);
    }

    LOG.debug("Created input channels {} from {}.", Arrays.toString(inputChannels), igdd);

    return inputGate;
  }