@Override
 public void forceAvailabilityMode(String cacheName, AvailabilityMode availabilityMode) {
   ClusterCacheStatus cacheStatus = cacheStatusMap.get(cacheName);
   if (cacheStatus != null) {
     cacheStatus.forceAvailabilityMode(availabilityMode);
   }
 }
 @Override
 public void setRebalancingEnabled(boolean enabled) {
   isRebalancingEnabled = enabled;
   for (ClusterCacheStatus cacheStatus : cacheStatusMap.values()) {
     cacheStatus.setRebalanceEnabled(enabled);
   }
 }
 @Override
 public void forceRebalance(String cacheName) {
   ClusterCacheStatus cacheStatus = cacheStatusMap.get(cacheName);
   if (cacheStatus != null) {
     cacheStatus.forceRebalance();
   }
 }
  private void recoverClusterStatus(
      int newViewId, boolean isMergeView, List<Address> clusterMembers) throws Exception {
    ReplicableCommand command =
        new CacheTopologyControlCommand(
            null, CacheTopologyControlCommand.Type.GET_STATUS, transport.getAddress(), newViewId);
    Map<Address, Object> statusResponses =
        executeOnClusterSync(command, getGlobalTimeout(), false, false);

    log.debugf("Got %d status responses. members are %s", statusResponses.size(), clusterMembers);
    Map<String, Map<Address, CacheStatusResponse>> responsesByCache = new HashMap<>();
    for (Map.Entry<Address, Object> responseEntry : statusResponses.entrySet()) {
      Address sender = responseEntry.getKey();
      Map<String, CacheStatusResponse> nodeStatus =
          (Map<String, CacheStatusResponse>) responseEntry.getValue();
      for (Map.Entry<String, CacheStatusResponse> statusEntry : nodeStatus.entrySet()) {
        String cacheName = statusEntry.getKey();

        Map<Address, CacheStatusResponse> cacheResponses = responsesByCache.get(cacheName);
        if (cacheResponses == null) {
          cacheResponses = new HashMap<>();
          responsesByCache.put(cacheName, cacheResponses);
        }
        cacheResponses.put(sender, statusEntry.getValue());
      }
    }

    for (Map.Entry<String, Map<Address, CacheStatusResponse>> e : responsesByCache.entrySet()) {
      ClusterCacheStatus cacheStatus = initCacheStatusIfAbsent(e.getKey());
      cacheStatus.doMergePartitions(e.getValue(), clusterMembers, isMergeView);
    }
  }
  public void updateCacheMembers(List<Address> newClusterMembers) throws Exception {
    log.tracef("Updating cluster members for all the caches. New list is %s", newClusterMembers);

    for (ClusterCacheStatus cacheStatus : cacheStatusMap.values()) {
      cacheStatus.doHandleClusterView(newClusterMembers);
    }
  }
  @Override
  public void handleRebalanceCompleted(
      String cacheName, Address node, int topologyId, Throwable throwable, int viewId)
      throws Exception {
    if (throwable != null) {
      // TODO We could try to update the pending CH such that nodes reporting errors are not
      // considered to hold any state
      // For now we are just logging the error and proceeding as if the rebalance was successful
      // everywhere
      log.rebalanceError(cacheName, node, throwable);
    }

    CLUSTER.rebalanceCompleted(cacheName, node, topologyId);

    ClusterCacheStatus cacheStatus = cacheStatusMap.get(cacheName);
    if (cacheStatus == null || !cacheStatus.isRebalanceInProgress()) {
      log.debugf(
          "Ignoring rebalance confirmation from %s "
              + "for cache %s because it doesn't have a cache status entry",
          node, cacheName);
      return;
    }

    cacheStatus.doConfirmRebalance(node, topologyId);
  }
 @Override
 public RebalancingStatus getRebalancingStatus(String cacheName) {
   ClusterCacheStatus cacheStatus = cacheStatusMap.get(cacheName);
   if (cacheStatus != null) {
     return cacheStatus.getRebalancingStatus();
   } else {
     return RebalancingStatus.PENDING;
   }
 }
 @Override
 public void setRebalancingEnabled(String cacheName, boolean enabled) {
   if (cacheName == null) {
     setRebalancingEnabled(enabled);
   } else {
     ClusterCacheStatus clusterCacheStatus = cacheStatusMap.get(cacheName);
     if (clusterCacheStatus != null) clusterCacheStatus.setRebalanceEnabled(enabled);
   }
 }
  @Override
  public CacheStatusResponse handleJoin(
      String cacheName, Address joiner, CacheJoinInfo joinInfo, int viewId) throws Exception {
    waitForView(viewId);
    if (isShuttingDown) {
      log.debugf(
          "Ignoring join request from %s for cache %s, the local cache manager is shutting down",
          joiner, cacheName);
      return null;
    }

    ClusterCacheStatus cacheStatus = initCacheStatusIfAbsent(cacheName);
    return cacheStatus.doJoin(joiner, joinInfo);
  }
  public void updateCacheMembers(List<Address> newClusterMembers) throws Exception {
    log.tracef("Updating cluster members for all the caches. New list is %s", newClusterMembers);
    try {
      // If we get a SuspectException here, it means we will have a new view soon and we can ignore
      // this one.
      confirmMembersAvailable();
    } catch (SuspectException e) {
      log.tracef("Node %s left while updating cache members", e.getSuspect());
      return;
    }

    for (ClusterCacheStatus cacheStatus : cacheStatusMap.values()) {
      cacheStatus.doHandleClusterView();
    }
  }
 @Override
 public void setRebalancingEnabled(boolean enabled) {
   if (enabled) {
     if (!globalRebalancingEnabled) {
       CLUSTER.rebalancingEnabled();
     }
   } else {
     if (globalRebalancingEnabled) {
       CLUSTER.rebalancingSuspended();
     }
   }
   globalRebalancingEnabled = enabled;
   for (ClusterCacheStatus cacheStatus : cacheStatusMap.values()) {
     cacheStatus.startQueuedRebalance();
   }
 }
  @Override
  public void handleLeave(String cacheName, Address leaver, int viewId) throws Exception {
    if (isShuttingDown) {
      log.debugf(
          "Ignoring leave request from %s for cache %s, the local cache manager is shutting down",
          leaver, cacheName);
      return;
    }

    ClusterCacheStatus cacheStatus = cacheStatusMap.get(cacheName);
    if (cacheStatus == null) {
      // This can happen if we've just become coordinator
      log.tracef(
          "Ignoring leave request from %s for cache %s because it doesn't have a cache status entry");
      return;
    }
    cacheStatus.doLeave(leaver);
  }