private Iterable<? extends CommittedBundle<?>> commitBundles(
     Iterable<? extends UncommittedBundle<?>> bundles) {
   ImmutableList.Builder<CommittedBundle<?>> completed = ImmutableList.builder();
   for (UncommittedBundle<?> inProgress : bundles) {
     AppliedPTransform<?, ?, ?> producing =
         inProgress.getPCollection().getProducingTransformInternal();
     TransformWatermarks watermarks = watermarkManager.getWatermarks(producing);
     CommittedBundle<?> committed =
         inProgress.commit(watermarks.getSynchronizedProcessingOutputTime());
     // Empty bundles don't impact watermarks and shouldn't trigger downstream execution, so
     // filter them out
     if (!Iterables.isEmpty(committed.getElements())) {
       completed.add(committed);
     }
   }
   return completed.build();
 }
 /**
  * Handle the provided {@link InProcessTransformResult}, produced after evaluating the provided
  * {@link CommittedBundle} (potentially null, if the result of a root {@link PTransform}).
  *
  * <p>The result is the output of running the transform contained in the {@link
  * InProcessTransformResult} on the contents of the provided bundle.
  *
  * @param completedBundle the bundle that was processed to produce the result. Potentially {@code
  *     null} if the transform that produced the result is a root transform
  * @param completedTimers the timers that were delivered to produce the {@code completedBundle},
  *     or an empty iterable if no timers were delivered
  * @param result the result of evaluating the input bundle
  * @return the committed bundles contained within the handled {@code result}
  */
 public CommittedResult handleResult(
     @Nullable CommittedBundle<?> completedBundle,
     Iterable<TimerData> completedTimers,
     InProcessTransformResult result) {
   Iterable<? extends CommittedBundle<?>> committedBundles =
       commitBundles(result.getOutputBundles());
   // Update watermarks and timers
   EnumSet<OutputType> outputTypes = EnumSet.copyOf(result.getOutputTypes());
   if (Iterables.isEmpty(committedBundles)) {
     outputTypes.remove(OutputType.BUNDLE);
   } else {
     outputTypes.add(OutputType.BUNDLE);
   }
   CommittedResult committedResult =
       CommittedResult.create(
           result,
           completedBundle == null
               ? null
               : completedBundle.withElements((Iterable) result.getUnprocessedElements()),
           committedBundles,
           outputTypes);
   watermarkManager.updateWatermarks(
       completedBundle,
       result.getTimerUpdate().withCompletedTimers(completedTimers),
       committedResult,
       result.getWatermarkHold());
   // Update counters
   if (result.getCounters() != null) {
     mergedCounters.merge(result.getCounters());
   }
   // Update state internals
   CopyOnAccessInMemoryStateInternals<?> theirState = result.getState();
   if (theirState != null) {
     CopyOnAccessInMemoryStateInternals<?> committedState = theirState.commit();
     StepAndKey stepAndKey =
         StepAndKey.of(
             result.getTransform(), completedBundle == null ? null : completedBundle.getKey());
     if (!committedState.isEmpty()) {
       applicationStateInternals.put(stepAndKey, committedState);
     } else {
       applicationStateInternals.remove(stepAndKey);
     }
   }
   return committedResult;
 }
 @Override
 public <T> UncommittedBundle<T> createBundle(CommittedBundle<?> input, PCollection<T> output) {
   return InProcessBundle.create(output, input.getKey());
 }