private ShardSpecs determineShardSpecs(
      final TaskToolbox toolbox,
      final FirehoseFactory firehoseFactory,
      final File firehoseTempDir,
      @Nullable final Integer maxRowsPerSegment
  ) throws IOException
  {
    final ObjectMapper jsonMapper = toolbox.getObjectMapper();
    final IndexTuningConfig tuningConfig = ingestionSchema.getTuningConfig();
    final IndexIOConfig ioConfig = ingestionSchema.getIOConfig();

    final GranularitySpec granularitySpec = ingestionSchema.getDataSchema().getGranularitySpec();

    // Must determine intervals if unknown, since we acquire all locks before processing any data.
    final boolean determineIntervals = !granularitySpec.bucketIntervals().isPresent();

    // Must determine partitions if rollup is guaranteed and the user didn't provide a specific value.
    final boolean determineNumPartitions = tuningConfig.getNumShards() == null
                                           && isGuaranteedRollup(ioConfig, tuningConfig);

    // if we were given number of shards per interval and the intervals, we don't need to scan the data
    if (!determineNumPartitions && !determineIntervals) {
      log.info("Skipping determine partition scan");
      return createShardSpecWithoutInputScan(
          jsonMapper,
          granularitySpec,
          ioConfig,
          tuningConfig
      );
    } else {
      // determine intervals containing data and prime HLL collectors
      return createShardSpecsFromInput(
          jsonMapper,
          ingestionSchema,
          firehoseFactory,
          firehoseTempDir,
          granularitySpec,
          tuningConfig,
          determineIntervals,
          determineNumPartitions,
          maxRowsPerSegment
      );
    }
  }
private ShardSpecs determineShardSpecs ( final TaskToolbox toolbox , final FirehoseFactory firehoseFactory , final File firehoseTempDir , @ Nullable final Integer maxRowsPerSegment ) throws IOException { final ObjectMapper jsonMapper = toolbox . getObjectMapper ( ) ; final IndexTuningConfig tuningConfig = ingestionSchema . getTuningConfig ( ) ; final IndexIOConfig ioConfig = ingestionSchema . getIOConfig ( ) ; final GranularitySpec granularitySpec = ingestionSchema . getDataSchema ( ) . getGranularitySpec ( ) ; final boolean determineIntervals = ! granularitySpec . bucketIntervals ( ) . isPresent ( ) ; final boolean determineNumPartitions = tuningConfig . getNumShards ( ) == null && isGuaranteedRollup ( ioConfig , tuningConfig ) ; if ( ! determineNumPartitions && ! determineIntervals ) { log . info ( "Skipping determine partition scan" ) ; return createShardSpecWithoutInputScan ( jsonMapper , granularitySpec , ioConfig , tuningConfig ) ; } else { return createShardSpecsFromInput ( jsonMapper , ingestionSchema , firehoseFactory , firehoseTempDir , granularitySpec , tuningConfig , determineIntervals , determineNumPartitions , maxRowsPerSegment ) ; } }
Determines intervals and shardSpecs for input data.  This method first checks that it must determine intervals and
shardSpecs by itself.  Intervals must be determined if they are not specified in {@link GranularitySpec}.
ShardSpecs must be determined if the perfect rollup must be guaranteed even though the number of shards is not
specified in {@link IndexTuningConfig}.
<P/>
If both intervals and shardSpecs don't have to be determined, this method simply returns {@link ShardSpecs} for the
given intervals.  Here, if {@link IndexTuningConfig#numShards} is not specified, {@link NumberedShardSpec} is used.
<p/>
If one of intervals or shardSpecs need to be determined, this method reads the entire input for determining one of
them.  If the perfect rollup must be guaranteed, {@link HashBasedNumberedShardSpec} is used for hash partitioning
of input data.  In the future we may want to also support single-dimension partitioning.

@return generated {@link ShardSpecs} representing a map of intervals and corresponding shard specs