private boolean doFlush(boolean applyAllDeletes) throws IOException {
    if (tragedy != null) {
      throw new IllegalStateException("this writer hit an unrecoverable error; cannot flush", tragedy);
    }

    doBeforeFlush();
    testPoint("startDoFlush");
    boolean success = false;
    try {

      if (infoStream.isEnabled("IW")) {
        infoStream.message("IW", "  start flush: applyAllDeletes=" + applyAllDeletes);
        infoStream.message("IW", "  index before flush " + segString());
      }
      boolean anyChanges = false;
      
      synchronized (fullFlushLock) {
        boolean flushSuccess = false;
        try {
          anyChanges = docWriter.flushAllThreads();
          if (!anyChanges) {
            // flushCount is incremented in flushAllThreads
            flushCount.incrementAndGet();
          }
          flushSuccess = true;
        } finally {
          docWriter.finishFullFlush(this, flushSuccess);
          processEvents(false, true);
        }
      }
      synchronized(this) {
        anyChanges |= maybeApplyDeletes(applyAllDeletes);
        doAfterFlush();
        success = true;
        return anyChanges;
      }
    } catch (AbortingException | VirtualMachineError tragedy) {
      tragicEvent(tragedy, "doFlush");
      // never hit
      return false;
    } finally {
      if (!success) {
        if (infoStream.isEnabled("IW")) {
          infoStream.message("IW", "hit exception during flush");
        }
      }
    }
  }