class RoundRobinLocator implements Locator {

  @Override
  public void dispatch(final Request<? extends Response> request, final List<Node> nodes,
                       final ClusterConfig config, final CoreContext ctx) {
    if (!checkServiceNotAvailable(request, config)) {
      return;
    }

    boolean isTargeted = request instanceof TargetedRequest;

    if (!isTargeted && !config.hasClusterOrBucketConfig()) {
      boolean globalLoadInProgress =  ctx.core().configurationProvider().globalConfigLoadInProgress();
      boolean bucketLoadInProgress =ctx.core().configurationProvider().bucketConfigLoadInProgress();
      boolean loadInProgress = globalLoadInProgress || bucketLoadInProgress;

      if (loadInProgress) {
        RetryOrchestrator.maybeRetry(
          ctx,
          request,
          bucketLoadInProgress ? RetryReason.BUCKET_OPEN_IN_PROGRESS : RetryReason.GLOBAL_CONFIG_LOAD_IN_PROGRESS
        );
      } else {
        request.fail(FeatureNotAvailableException.clusterLevelQuery(serviceType));
      }
      return;
    }

    List<Node> filteredNodes = filterNodes(nodes, request, config);
    if (filteredNodes.isEmpty()) {
      if (serviceShowsUpInConfig(config)) {
        // No node has the service enabled, but it shows up in the config. This is a race condition,
        // likely the node/service is currently in progress of being configured, so let's send it into
        // retry and wait until it can be dispatched.
        RetryOrchestrator.maybeRetry(ctx, request, RetryReason.NODE_NOT_AVAILABLE);
      } else {
        // No node in the cluster has the service enabled and it does not show up in the bucket config,
        // so we need to cancel the request with a service not available exception. Either the cluster is
        // not configured with the service in the first place or a failover happened and suddenly there
        // is no node in the cluster anymore which can serve the request. In any case sending it into
        // retry will not help resolve the situation so let's make it clear in the exception what's
        //going on.
        request.fail(new ServiceNotAvailableException(
          "The " + request.serviceType().ident()
            + " service is not available in the cluster.",
          new GenericRequestErrorContext(request)
        ));
      }
      return;
    }

    if (isTargeted) {
      dispatchTargeted(request, filteredNodes, ctx);
    } else {
      dispatchUntargeted(request, filteredNodes, ctx);
    }
  }

  public  RoundRobinLocator(final ServiceType serviceType);
    RoundRobinLocator(final ServiceType serviceType, final long initialValue);

}