code: public void flush(final long targetCounter) throws IOException, JournalClosedException {
      // Return if flushed.
      if (targetCounter <= mFlushCounter.get()) {
        return;
      }
  
      // Submit the ticket for flush thread to process.
      FlushTicket ticket = new FlushTicket(targetCounter);
      try (LockResource lr = new LockResource(mTicketLock)) {
        mTicketList.add(ticket);
      }
  
      try {
        // Give a permit for flush thread to run.
        mFlushSemaphore.release();
  
        // Wait on the ticket until completed.
        ticket.waitCompleted();
      } catch (InterruptedException ie) {
        // Interpret interruption as cancellation.
        throw new AlluxioStatusException(Status.CANCELLED.withCause(ie));
      } catch (Throwable e) {
        // Filter, journal specific exception codes.
        if (e instanceof IOException) {
          throw (IOException) e;
        }
        if (e instanceof JournalClosedException) {
          throw (JournalClosedException) e;
        }
        // Not expected. throw internal error.
        throw new AlluxioStatusException(Status.INTERNAL.withCause(e));
      } finally {
        /**
         * Client can only try to reacquire the permit it has given
         * because the permit may or may not have been used by the flush thread.
         */
        mFlushSemaphore.tryAcquire();
      }
    }
docs: Submits a ticket to flush thread and waits until ticket is served.
  
  If the specified counter is already flushed, this is essentially a no-op.
  
  @param targetCounter the counter to flush