@Override
  public boolean verify() throws Exception {
    ClusterAccessor clusterAccessor = new ClusterAccessor(ClusterId.from(_clusterName), _accessor);
    Cluster cluster = clusterAccessor.readCluster();

    List<ParticipantId> liveInstances = new ArrayList<ParticipantId>();
    liveInstances.addAll(cluster.getLiveParticipantMap().keySet());
    boolean success = verifyLiveNodes(liveInstances);
    if (!success) {
      LOG.info(
          "liveNodes not match, expect: " + _expectSortedLiveNodes + ", actual: " + liveInstances);
      return false;
    }

    BestPossibleStateOutput bestPossbileStates = calculateBestPossibleState(cluster);
    Map<String, ExternalView> externalViews =
        _accessor.getChildValuesMap(_keyBuilder.externalViews());

    // TODO all ideal-states should be included in external-views

    for (String resourceName : externalViews.keySet()) {
      ExternalView externalView = externalViews.get(resourceName);
      ResourceAssignment assignment =
          bestPossbileStates.getResourceAssignment(ResourceId.from(resourceName));
      final Map<PartitionId, Map<String, String>> bestPossibleState = Maps.newHashMap();
      for (PartitionId partitionId : assignment.getMappedPartitionIds()) {
        Map<String, String> rawStateMap =
            ResourceAssignment.stringMapFromReplicaMap(assignment.getReplicaMap(partitionId));
        bestPossibleState.put(partitionId, rawStateMap);
      }
      success = verifyExternalView(externalView, bestPossibleState);
      if (!success) {
        LOG.info("external-view for resource: " + resourceName + " not match");
        return false;
      }
    }

    return true;
  }
Beispiel #2
0
  @Override
  public ResourceAssignment computeResourceMapping(
      RebalancerConfiguration rebalancerConfig,
      ResourceAssignment prevAssignment,
      Cluster cluster,
      ResourceCurrentState currentState) {
    FullAutoRebalancerConfig config =
        BasicRebalancerConfig.convert(rebalancerConfig, FullAutoRebalancerConfig.class);
    StateModelDefinition stateModelDef =
        cluster.getStateModelMap().get(config.getStateModelDefId());
    // Compute a preference list based on the current ideal state
    List<PartitionId> partitions = new ArrayList<PartitionId>(config.getPartitionSet());
    Map<ParticipantId, Participant> liveParticipants = cluster.getLiveParticipantMap();
    Map<ParticipantId, Participant> allParticipants = cluster.getParticipantMap();
    int replicas = -1;
    if (partitions.size() > 0 && config.getAnyLiveParticipant(partitions.get(0))) {
      replicas = liveParticipants.size();
    } else {
      replicas = config.getReplicaCount();
    }

    // count how many replicas should be in each state
    Map<State, String> upperBounds =
        ConstraintBasedAssignment.stateConstraints(
            stateModelDef, config.getResourceId(), cluster.getConfig());
    LinkedHashMap<State, Integer> stateCountMap =
        ConstraintBasedAssignment.stateCount(
            upperBounds, stateModelDef, liveParticipants.size(), replicas);

    // get the participant lists
    List<ParticipantId> liveParticipantList =
        new ArrayList<ParticipantId>(liveParticipants.keySet());
    List<ParticipantId> allParticipantList =
        new ArrayList<ParticipantId>(cluster.getParticipantMap().keySet());

    // compute the current mapping from the current state
    Map<PartitionId, Map<ParticipantId, State>> currentMapping =
        currentMapping(config, currentState, stateCountMap);

    // If there are nodes tagged with resource, use only those nodes
    // If there are nodes tagged with resource name, use only those nodes
    Set<ParticipantId> taggedNodes = new HashSet<ParticipantId>();
    Set<ParticipantId> taggedLiveNodes = new HashSet<ParticipantId>();
    if (config.getParticipantGroupTag() != null) {
      for (ParticipantId participantId : allParticipantList) {
        if (cluster
            .getParticipantMap()
            .get(participantId)
            .hasTag(config.getParticipantGroupTag())) {
          taggedNodes.add(participantId);
          if (liveParticipants.containsKey(participantId)) {
            taggedLiveNodes.add(participantId);
          }
        }
      }
      if (!taggedLiveNodes.isEmpty()) {
        // live nodes exist that have this tag
        if (LOG.isDebugEnabled()) {
          LOG.debug(
              "found the following participants with tag "
                  + config.getParticipantGroupTag()
                  + " for "
                  + config.getResourceId()
                  + ": "
                  + taggedLiveNodes);
        }
      } else if (taggedNodes.isEmpty()) {
        // no live nodes and no configured nodes have this tag
        LOG.warn(
            "Resource "
                + config.getResourceId()
                + " has tag "
                + config.getParticipantGroupTag()
                + " but no configured participants have this tag");
      } else {
        // configured nodes have this tag, but no live nodes have this tag
        LOG.warn(
            "Resource "
                + config.getResourceId()
                + " has tag "
                + config.getParticipantGroupTag()
                + " but no live participants have this tag");
      }
      allParticipantList = new ArrayList<ParticipantId>(taggedNodes);
      liveParticipantList = new ArrayList<ParticipantId>(taggedLiveNodes);
    }

    // determine which nodes the replicas should live on
    int maxPartition = config.getMaxPartitionsPerParticipant();
    if (LOG.isDebugEnabled()) {
      LOG.debug("currentMapping: " + currentMapping);
      LOG.debug("stateCountMap: " + stateCountMap);
      LOG.debug("liveNodes: " + liveParticipantList);
      LOG.debug("allNodes: " + allParticipantList);
      LOG.debug("maxPartition: " + maxPartition);
    }
    ReplicaPlacementScheme placementScheme = new DefaultPlacementScheme();
    _algorithm =
        new AutoRebalanceStrategy(
            config.getResourceId(), partitions, stateCountMap, maxPartition, placementScheme);
    ZNRecord newMapping =
        _algorithm.typedComputePartitionAssignment(
            liveParticipantList, currentMapping, allParticipantList);

    if (LOG.isInfoEnabled()) {
      LOG.info("newMapping: " + newMapping);
    }

    // compute a full partition mapping for the resource
    if (LOG.isDebugEnabled()) {
      LOG.debug("Processing resource:" + config.getResourceId());
    }
    ResourceAssignment partitionMapping = new ResourceAssignment(config.getResourceId());
    for (PartitionId partition : partitions) {
      Set<ParticipantId> disabledParticipantsForPartition =
          ConstraintBasedAssignment.getDisabledParticipants(allParticipants, partition);
      List<String> rawPreferenceList = newMapping.getListField(partition.toString());
      if (rawPreferenceList == null) {
        rawPreferenceList = Collections.emptyList();
      }
      List<ParticipantId> preferenceList =
          Lists.transform(
              rawPreferenceList,
              new Function<String, ParticipantId>() {
                @Override
                public ParticipantId apply(String participantName) {
                  return ParticipantId.from(participantName);
                }
              });
      preferenceList =
          ConstraintBasedAssignment.getPreferenceList(cluster, partition, preferenceList);
      Map<ParticipantId, State> bestStateForPartition =
          ConstraintBasedAssignment.computeAutoBestStateForPartition(
              upperBounds,
              liveParticipants.keySet(),
              stateModelDef,
              preferenceList,
              currentState.getCurrentStateMap(config.getResourceId(), partition),
              disabledParticipantsForPartition);
      partitionMapping.addReplicaMap(partition, bestStateForPartition);
    }
    return partitionMapping;
  }