public void seek(int startingFileOffset, long startingRecordOffset) {
    // It means file is empty.
    if (taskSize == 0) {
      return;
    }
    Preconditions.checkState(
        fileOffset == -1, "Seek should be called before any other iterator actions");
    // skip files
    Preconditions.checkState(
        startingFileOffset < taskSize,
        "Invalid starting file offset %s for combined scan task with %s files.",
        startingFileOffset,
        taskSize);
    for (long i = 0L; i < startingFileOffset; ++i) {
      tasks.next();
    }

    updateCurrentIterator();
    // skip records within the file
    for (long i = 0; i < startingRecordOffset; ++i) {
      if (currentFileHasNext() && hasNext()) {
        next();
      } else {
        throw new IllegalStateException(
            String.format(
                "Invalid starting record offset %d for file %d from FileScanTask List.",
                startingRecordOffset, startingFileOffset));
      }
    }

    fileOffset = startingFileOffset;
    recordOffset = startingRecordOffset;
  }
(startingFileOffset, startingRecordOffset) points to the next row that the reader should resume
from. E.g., if the seek position is (file=0, record=1), seek moves the iterator position to the
second row in file 0. When next() is called after seek; the second row from file 0 should be
returned.
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/read/source/DataIterator.java