/**
   * TODO: chunkNumericPK definition.
   *
   * @param table
   * @param columns
   * @param chunkSize
   * @throws ReplicatorException
   * @throws InterruptedException
   */
  private void chunkNumericPK(Table table, String[] columns, long chunkSize)
      throws ReplicatorException, InterruptedException {
    // Retrieve PK range
    MinMax minmax = retrieveMinMaxCountPK(connection, table);

    if (minmax != null) {
      if (logger.isDebugEnabled())
        logger.debug(
            "Min = "
                + minmax.getMin()
                + " -- Max = "
                + minmax.getMax()
                + " -- Count = "
                + minmax.getCount());

      if (minmax.getCount() <= chunkSize)
        // Get the whole table at once
        chunks.put(new NumericChunk(table, columns));
      else {
        // Share the joy among threads,
        // if primary key is evenly distributed
        if (!minmax.isDecimal()) {
          long gap = (Long) minmax.getMax() - (Long) minmax.getMin();
          long blockSize = chunkSize * gap / minmax.getCount();

          long nbBlocks = gap / blockSize;
          if (gap % blockSize > 0) nbBlocks++;

          long start = (Long) minmax.getMin() - 1;
          long end;
          do {
            end = start + blockSize;
            if (end > (Long) minmax.getMax()) end = (Long) minmax.getMax();
            NumericChunk e = new NumericChunk(table, start, end, columns, nbBlocks);
            chunks.put(e);
            start = end;
          } while (start < (Long) minmax.getMax());
        } else {
          BigInteger start =
              ((BigDecimal) minmax.getMin())
                  .setScale(0, RoundingMode.FLOOR)
                  .toBigInteger()
                  .subtract(BigInteger.valueOf(1));

          BigInteger max =
              ((BigDecimal) minmax.getMax()).setScale(0, RoundingMode.CEILING).toBigInteger();

          BigInteger gap = max.subtract(start);

          BigInteger blockSize =
              gap.multiply(BigInteger.valueOf(chunkSize))
                  .divide(BigInteger.valueOf(minmax.getCount()));

          long nbBlocks = gap.divide(blockSize).longValue();

          if (!gap.remainder(blockSize).equals(BigInteger.ZERO)) {
            nbBlocks++;
            blockSize =
                gap.divide(BigInteger.valueOf(nbBlocks))
                    .add(
                        gap.remainder(blockSize).equals(BigInteger.ZERO)
                            ? BigInteger.ZERO
                            : BigInteger.ONE);
          }
          BigInteger end;
          do {
            end = start.add(blockSize);
            if (end.compareTo(
                    (((BigDecimal) minmax.getMax()).setScale(0, RoundingMode.CEILING))
                        .toBigInteger())
                == 1)
              end =
                  (((BigDecimal) minmax.getMax()).setScale(0, RoundingMode.CEILING)).toBigInteger();

            NumericChunk e = new NumericChunk(table, start, end, columns, nbBlocks);
            chunks.put(e);
            start = end;
          } while (start.compareTo(
                  (((BigDecimal) minmax.getMax()).setScale(0, RoundingMode.CEILING)).toBigInteger())
              == -1);
        }
      }
    } else {
      // table is empty or does not have a
      // good candidate as a PK for chunking.
      // Fall back to limit method
      chunks.put(new NumericChunk(table, columns));
    }
  }