@Override
  public SplitResult<ByteKeyRange> trySplit(double fractionOfRemainder) {
    // No split on an empty range.
    if (NO_KEYS.equals(range)
        || (!range.getEndKey().isEmpty() && range.getStartKey().equals(range.getEndKey()))) {
      return null;
    }
    // There is no more remaining work after the entire range has been claimed.
    if (lastAttemptedKey != null && lastAttemptedKey.isEmpty()) {
      return null;
    }

    ByteKey unprocessedRangeStartKey =
        (lastAttemptedKey == null) ? range.getStartKey() : next(lastAttemptedKey);
    ByteKey endKey = range.getEndKey();
    // There is no more space for split.
    if (!endKey.isEmpty() && unprocessedRangeStartKey.compareTo(endKey) >= 0) {
      return null;
    }

    // Treat checkpoint specially because {@link ByteKeyRange#interpolateKey} computes a key with
    // trailing zeros when fraction is 0.
    if (fractionOfRemainder == 0.0) {
      // If we haven't done any work, we should return the original range we were processing
      // as the checkpoint.
      if (lastAttemptedKey == null) {
        // We update our current range to an interval that contains no elements.
        ByteKeyRange rval = range;
        range =
            range.getStartKey().isEmpty()
                ? NO_KEYS
                : ByteKeyRange.of(range.getStartKey(), range.getStartKey());
        return SplitResult.of(range, rval);
      } else {
        range = ByteKeyRange.of(range.getStartKey(), unprocessedRangeStartKey);
        return SplitResult.of(range, ByteKeyRange.of(unprocessedRangeStartKey, endKey));
      }
    }

    ByteKeyRange unprocessedRange = ByteKeyRange.of(unprocessedRangeStartKey, range.getEndKey());
    ByteKey splitPos;
    try {
      // The interpolateKey shouldn't return empty key. Please refer to {@link
      // ByteKeyRange#interpolateKey}.
      splitPos = unprocessedRange.interpolateKey(fractionOfRemainder);
      checkState(!splitPos.isEmpty());
    } catch (Exception e) {
      // There is no way to interpolate a key based on provided fraction.
      return null;
    }
    // Computed splitPos is out of current tracking restriction.
    if (!range.getEndKey().isEmpty() && splitPos.compareTo(range.getEndKey()) >= 0) {
      return null;
    }

    range = ByteKeyRange.of(range.getStartKey(), splitPos);
    return SplitResult.of(range, ByteKeyRange.of(splitPos, endKey));
  }
@Test
  public void testTrySplit() throws Exception {
    ByteKeyRangeTracker tracker = ByteKeyRangeTracker.of(ByteKeyRange.ALL_KEYS);
    SplitResult<ByteKeyRange> res = tracker.trySplit(0.5);
    assertKeyRangeEqualExceptPadding(
        ByteKeyRange.of(ByteKey.EMPTY, ByteKey.of(0x80)), res.getPrimary());
    assertKeyRangeEqualExceptPadding(
        ByteKeyRange.of(ByteKey.of(0x80), ByteKey.EMPTY), res.getResidual());
    tracker.tryClaim(ByteKey.of(0x00));
    res = tracker.trySplit(0.5);
    assertKeyRangeEqualExceptPadding(
        ByteKeyRange.of(ByteKey.EMPTY, ByteKey.of(0x40)), res.getPrimary());
    assertKeyRangeEqualExceptPadding(
        ByteKeyRange.of(ByteKey.of(0x40), ByteKey.of(0x80)), res.getResidual());
    assertNull(tracker.trySplit(1));
  }