private synchronized void startTransaction(boolean haveReadLock) throws IOException {

    boolean success = false;
    try {
      if (infoStream != null)
        message("now start transaction");

      assert docWriter.getNumBufferedDeleteTerms() == 0 :
      "calling startTransaction with buffered delete terms not supported: numBufferedDeleteTerms=" + docWriter.getNumBufferedDeleteTerms();
      assert docWriter.getNumDocsInRAM() == 0 :
      "calling startTransaction with buffered documents not supported: numDocsInRAM=" + docWriter.getNumDocsInRAM();

      ensureOpen();

      // If a transaction is trying to roll back (because
      // addIndexes hit an exception) then wait here until
      // that's done:
      synchronized(this) {
        while(stopMerges)
          doWait();
      }
      success = true;
    } finally {
      // Release the write lock if our caller held it, on
      // hitting an exception
      if (!success && haveReadLock)
        releaseRead();
    }

    if (haveReadLock) {
      upgradeReadToWrite();
    } else {
      acquireWrite();
    }

    success = false;
    try {
      localRollbackSegmentInfos = (SegmentInfos) segmentInfos.clone();

      assert !hasExternalSegments();

      localFlushedDocCount = docWriter.getFlushedDocCount();

      // We must "protect" our files at this point from
      // deletion in case we need to rollback:
      deleter.incRef(segmentInfos, false);

      success = true;
    } finally {
      if (!success)
        finishAddIndexes();
    }
  }