code: private CompletableFuture<WriterFlushResult> flushNormally(TimeoutTimer timer) {
          assert this.state.get() == AggregatorState.Writing : "flushNormally cannot be called if state == " + this.state;
          long traceId = LoggerHelpers.traceEnterWithContext(log, this.traceObjectId, "flushNormally", this.operations.size());
          WriterFlushResult result = new WriterFlushResult();
          AtomicBoolean canContinue = new AtomicBoolean(true);
          return Futures
                  .loop(
                          canContinue::get,
                          () -> flushOnce(timer),
                          partialResult -> {
                              canContinue.set(partialResult.getFlushedBytes() + partialResult.getMergedBytes() > 0);
                              result.withFlushResult(partialResult);
                          },
                          this.executor)
                  .thenApply(v -> {
                      LoggerHelpers.traceLeave(log, this.traceObjectId, "flushNormally", traceId, result);
                      return result;
                  });
      }
docs: Repeatedly flushes the contents of the Aggregator to the Storage as long as something immediate needs to be flushed,
  such as a Seal or Merge operation.
  
  @param timer Timer for the operation.
  @return A CompletableFuture that, when completed, will contain the result from the flush operation.