private long writeWALMetadata(Consumer<CompletableFuture<Long>> action) throws IOException {
    CompletableFuture<Long> future = new CompletableFuture<>();
    action.accept(future);
    try {
      return future.get(waitTimeout, TimeUnit.MILLISECONDS).longValue();
    } catch (InterruptedException e) {
      InterruptedIOException ioe = new InterruptedIOException();
      ioe.initCause(e);
      throw ioe;
    } catch (ExecutionException e) {
      Throwables.propagateIfPossible(e.getCause(), IOException.class);
      throw new RuntimeException(e.getCause());
    } catch (TimeoutException e) {
      throw new TimeoutIOException(e);
    }
  }
We have to call {@link AsyncFSOutput#getSyncedLength()} after {@link AsyncFSOutput#close()}
to get the final length synced to underlying filesystem because {@link AsyncFSOutput#close()}
may also flush some data to underlying filesystem.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AsyncProtobufLogWriter.java