@Override
  public synchronized boolean tryReturnRecordAt(boolean isAtSplitPoint, ByteKey recordStart) {
    if (done) {
      return false;
    }

    checkState(!(position == null && !isAtSplitPoint), "The first record must be at a split point");
    checkState(
        !(recordStart.compareTo(range.getStartKey()) < 0),
        "Trying to return record which is before the start key");
    checkState(
        !(position != null && recordStart.compareTo(position) < 0),
        "Trying to return record which is before the last-returned record");

    if (position == null) {
      range = range.withStartKey(recordStart);
    }
    position = recordStart;

    if (isAtSplitPoint) {
      if (!range.containsKey(recordStart)) {
        done = true;
        return false;
      }
      ++splitPointsSeen;
    }
    return true;
  }
  @Override
  public synchronized boolean trySplitAtPosition(ByteKey splitPosition) {
    // Unstarted.
    if (position == null) {
      LOG.warn(
          "{}: Rejecting split request at {} because no records have been returned.",
          this,
          splitPosition);
      return false;
    }

    // Started, but not after current position.
    if (splitPosition.compareTo(position) <= 0) {
      LOG.warn(
          "{}: Rejecting split request at {} because it is not after current position {}.",
          this,
          splitPosition,
          position);
      return false;
    }

    // Sanity check.
    if (!range.containsKey(splitPosition)) {
      LOG.warn(
          "{}: Rejecting split request at {} because it is not within the range.",
          this,
          splitPosition);
      return false;
    }

    range = range.withEndKey(splitPosition);
    return true;
  }