public ReadOperation(
     String operationName,
     Reader<?> reader,
     OutputReceiver[] receivers,
     String counterPrefix,
     String systemStageName,
     CounterSet.AddCounterMutator addCounterMutator,
     StateSampler stateSampler) {
   super(
       operationName,
       receivers,
       counterPrefix,
       addCounterMutator,
       stateSampler,
       reader.getStateSamplerStateKind());
   this.reader = reader;
   this.byteCount =
       addCounterMutator.addCounter(
           Counter.longs(bytesCounterName(counterPrefix, operationName), SUM));
   reader.addObserver(new ReaderObserver());
   reader.setStateSamplerAndOperationName(stateSampler, operationName);
   this.totalParallelismCounter =
       addCounterMutator.addCounter(
           Counter.doubles(totalParallelismCounterName(systemStageName), SUM));
   // Set only when a task is started or split.
   totalParallelismCounter.resetToValue(boundParallelism(reader.getTotalParallelism()));
   this.remainingParallelismCounter =
       addCounterMutator.addCounter(
           Counter.doubles(remainingParallelismCounterName(systemStageName), SUM));
 }
 private void setProgressFromIterator() {
   try {
     progress.set(readerIterator.getProgress());
     remainingParallelismCounter.resetToValue(
         boundParallelism(readerIterator.getRemainingParallelism()));
   } catch (UnsupportedOperationException e) {
     // Ignore: same semantics as null.
   } catch (Exception e) {
     // This is not a normal situation, but should not kill the task.
     LOG.warn("Progress estimation failed", e);
   }
 }
 /** Relays the split request to {@code ReaderIterator}. */
 public Reader.DynamicSplitResult requestDynamicSplit(Reader.DynamicSplitRequest splitRequest) {
   synchronized (initializationStateLock) {
     if (isFinished()) {
       LOG.warn("Iterator is in the Finished state, returning null stop position.");
       return null;
     }
     if (readerIterator == null) {
       LOG.warn("Iterator has not been initialized, refusing to split at {}", splitRequest);
       return null;
     }
     Reader.DynamicSplitResult result = readerIterator.requestDynamicSplit(splitRequest);
     if (result != null) {
       // After a successful split, the stop position changed and progress has to be recomputed.
       setProgressFromIterator();
       totalParallelismCounter.resetToValue(boundParallelism(reader.getTotalParallelism()));
     }
     return result;
   }
 }