code: private ScanPlan createPlan(String scanId, ScanOptions options) {
          ScanPlan plan = new ScanPlan(scanId, options);
  
          for (String placement : options.getPlacements()) {
              String cluster = _dataTools.getPlacementCluster(placement);
              ScanRangeSplits scanRangeSplits = _dataTools.getScanRangeSplits(placement, options.getRangeScanSplitSize(), Optional.<ScanRange>absent());
  
              if (!options.isScanByAZ()) {
                  // Optionally we can reduce load across the ring by limiting scans AZ at a time.  However, the caller
                  // has requested to scan all token ranges as quickly as possible, so collapse all token ranges into a
                  // single group.
                  scanRangeSplits = scanRangeSplits.combineGroups();
              }
  
              for (ScanRangeSplits.SplitGroup splitGroup : scanRangeSplits.getSplitGroups()) {
                  // Start a new batch, indicating the subsequent token ranges can be scanned in parallel
                  plan.startNewBatchForCluster(cluster);
                  // Add the scan ranges associated with each token range in the split group to the batch
                  for (ScanRangeSplits.TokenRange tokenRange : splitGroup.getTokenRanges()) {
                      plan.addTokenRangeToCurrentBatchForCluster(cluster, placement, tokenRange.getScanRanges());
                  }
              }
          }
  
          return plan;
      }
docs: Returns a ScanPlan based on the Cassandra rings and token ranges.