code: private CompletableFuture<WriterFlushResult> mergeIfNecessary(WriterFlushResult flushResult, TimeoutTimer timer) {
          ensureInitializedAndNotClosed();
          long traceId = LoggerHelpers.traceEnterWithContext(log, this.traceObjectId, "mergeIfNecessary");
  
          StorageOperation first = this.operations.getFirst();
          if (first == null || !(first instanceof MergeSegmentOperation)) {
              // Either no operation or first operation is not a MergeTransaction. Nothing to do.
              LoggerHelpers.traceLeave(log, this.traceObjectId, "mergeIfNecessary", traceId, flushResult);
              return CompletableFuture.completedFuture(flushResult);
          }
  
          MergeSegmentOperation mergeSegmentOperation = (MergeSegmentOperation) first;
          UpdateableSegmentMetadata transactionMetadata = this.dataSource.getStreamSegmentMetadata(mergeSegmentOperation.getSourceSegmentId());
          return mergeWith(transactionMetadata, mergeSegmentOperation, timer)
                  .thenApply(mergeResult -> {
                      flushResult.withFlushResult(mergeResult);
                      LoggerHelpers.traceLeave(log, this.traceObjectId, "mergeIfNecessary", traceId, flushResult);
                      return flushResult;
                  });
      }
docs: Executes a merger of a Transaction StreamSegment into this one.
  Conditions for merger:
  <ul>
  <li> This StreamSegment is stand-alone (not a Transaction).
  <li> The next outstanding operation is a MergeSegmentOperation for a Transaction StreamSegment of this StreamSegment.
  <li> The StreamSegment to merge is not deleted, it is sealed and is fully flushed to Storage.
  </ul>
  Effects of the merger:
  <ul> The entire contents of the given Transaction StreamSegment will be concatenated to this StreamSegment as one unit.
  <li> The metadata for this StreamSegment will be updated to reflect the new length of this StreamSegment.
  <li> The given Transaction Segment will cease to exist.
  </ul>
  <p>
  Note that various other data integrity checks are done pre and post merger as part of this operation which are meant
  to ensure the StreamSegment is not in a corrupted state.
  
  @param flushResult The flush result from the previous chained operation.
  @param timer       Timer for the operation.
  @return A CompletableFuture that, when completed, will contain the number of bytes that were merged into this
  StreamSegment. If failed, the Future will contain the exception that caused it.