private boolean updateContainerState()

in hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/AbstractContainerReportHandler.java [240:332]


  private boolean updateContainerState(final DatanodeDetails datanode,
                                    final ContainerInfo container,
                                    final ContainerReplicaProto replica,
                                    final EventPublisher publisher,
      Object detailsForLogging) throws IOException, InvalidStateTransitionException {

    final ContainerID containerId = container.containerID();
    boolean replicaIsEmpty = replica.hasIsEmpty() && replica.getIsEmpty();

    switch (container.getState()) {
    case OPEN:
      // If the state of a container is OPEN and a replica is in different state, finalize the container.
      if (replica.getState() != State.OPEN) {
        getLogger().info("FINALIZE (i.e. CLOSING) {}", detailsForLogging);
        containerManager.updateContainerState(containerId, LifeCycleEvent.FINALIZE);
      }
      return false;
    case CLOSING:
      // When the container is in CLOSING state, a replica can be either OPEN, CLOSING, QUASI_CLOSED or CLOSED

      // If the replica are either in OPEN or CLOSING state, do nothing.

      // If the replica is in QUASI_CLOSED state, move the container to QUASI_CLOSED state.
      if (replica.getState() == State.QUASI_CLOSED) {
        getLogger().info("QUASI_CLOSE {}", detailsForLogging);
        containerManager.updateContainerState(containerId, LifeCycleEvent.QUASI_CLOSE);
        return false;
      }

      // If the replica is in CLOSED state, mark the container as CLOSED.
      if (replica.getState() == State.CLOSED) {
        /*
        For an EC container, only the first index and the parity indexes are
        guaranteed to have block data. So, update the container's state in SCM
        only if replica index is one of these indexes.
         */
        if (container.getReplicationType()
            .equals(HddsProtos.ReplicationType.EC)) {
          int replicaIndex = replica.getReplicaIndex();
          int dataNum =
              ((ECReplicationConfig)container.getReplicationConfig()).getData();
          if (replicaIndex != 1 && replicaIndex <= dataNum) {
            return false;
          }
        }

        if (bcsidMismatched(container, replica, detailsForLogging)) {
          return true;
        }
        getLogger().info("CLOSE {}", detailsForLogging);
        containerManager.updateContainerState(containerId, LifeCycleEvent.CLOSE);
      }
      return false;
    case QUASI_CLOSED:
      // The container is QUASI_CLOSED, this means that at least one of the replicas was QUASI_CLOSED.
      // Now replicas can be in either OPEN, CLOSING, QUASI_CLOSED or CLOSED

      // If one of the replica is in CLOSED state, mark the container as CLOSED.
      if (replica.getState() == State.CLOSED) {
        if (bcsidMismatched(container, replica, detailsForLogging)) {
          return true;
        }
        getLogger().info("FORCE_CLOSE for {}", detailsForLogging);
        containerManager.updateContainerState(containerId, LifeCycleEvent.FORCE_CLOSE);
      }
      return false;
    case CLOSED:
      // The container is already in closed state. do nothing.
      return false;
    case DELETED:
      // If container is in DELETED state and the reported replica is empty, delete the empty replica.
      // We should also do this for DELETING containers and currently DeletingContainerHandler does that
      if (replicaIsEmpty) {
        deleteReplica(containerId, datanode, publisher, "DELETED", false, detailsForLogging);
        return false;
      }
      // HDDS-12421: fall-through to case DELETING
    case DELETING:
      // HDDS-11136: If a DELETING container has a non-empty CLOSED replica, transition the container to CLOSED
      // HDDS-12421: If a DELETING or DELETED container has a non-empty replica, transition the container to CLOSED
      boolean replicaStateAllowed = (replica.getState() != State.INVALID && replica.getState() != State.DELETED);
      if (!replicaIsEmpty && replicaStateAllowed) {
        getLogger().info("transitionDeletingToClosed due to non-empty CLOSED replica (keyCount={}) for {}",
            replica.getKeyCount(), detailsForLogging);
        containerManager.transitionDeletingOrDeletedToClosedState(containerId);
      }
      return false;
    default:
      getLogger().error("Replica not processed due to container state {}: {}",
          container.getState(), detailsForLogging);
      return false;
    }
  }