| Code with Finding: | 
                        
                                                                                                        class IndexWriter {
  /** Walk through all files referenced by the current
   *  segmentInfos and ask the Directory to sync each file,
   *  if it wasn't already.  If that succeeds, then we
   *  prepare a new segments_N file but do not fully commit
   *  it. */
  private void startCommit(long sizeInBytes, Map commitUserData) throws IOException {
    assert testPoint("startStartCommit");
    if (hitOOM) {
      throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot commit");
    }
    try {
      if (infoStream != null)
        message("startCommit(): start sizeInBytes=" + sizeInBytes);
      if (sizeInBytes > 0)
        syncPause(sizeInBytes);
      SegmentInfos toSync = null;
      final long myChangeCount;
      synchronized(this) {
        // sizeInBytes > 0 means this is an autoCommit at
        // the end of a merge.  If at this point stopMerges
        // is true (which means a rollback() or
        // rollbackTransaction() is waiting for us to
        // finish), we skip the commit to avoid deadlock
        if (sizeInBytes > 0 && stopMerges)
          return;
        // Wait for any running addIndexes to complete
        // first, then block any from running until we've
        // copied the segmentInfos we intend to sync:
        blockAddIndexes(false);
        // On commit the segmentInfos must never
        // reference a segment in another directory:
        assert !hasExternalSegments();
        try {
          assert lastCommitChangeCount <= changeCount;
          if (changeCount == lastCommitChangeCount) {
            if (infoStream != null)
              message("  skip startCommit(): no changes pending");
            return;
          }
          // First, we clone & incref the segmentInfos we intend
          // to sync, then, without locking, we sync() each file
          // referenced by toSync, in the background.  Multiple
          // threads can be doing this at once, if say a large
          // merge and a small merge finish at the same time:
          if (infoStream != null)
            message("startCommit index=" + segString(segmentInfos) + " changeCount=" + changeCount);
          
          readerPool.commit();
          
          toSync = (SegmentInfos) segmentInfos.clone();
          if (commitUserData != null)
            toSync.setUserData(commitUserData);
          deleter.incRef(toSync, false);
          myChangeCount = changeCount;
          Iterator it = toSync.files(directory, false).iterator();
          while(it.hasNext()) {
            String fileName = (String) it.next();
            assert directory.fileExists(fileName): "file " + fileName + " does not exist";
          }
        } finally {
          resumeAddIndexes();
        }
      }
      assert testPoint("midStartCommit");
      boolean setPending = false;
      try {
        // Loop until all files toSync references are sync'd:
        while(true) {
          final Collection pending = new ArrayList();
          Iterator it = toSync.files(directory, false).iterator();
          while(it.hasNext()) {
            final String fileName = (String) it.next();
            if (startSync(fileName, pending)) {
              boolean success = false;
              try {
                // Because we incRef'd this commit point, above,
                // the file had better exist:
                assert directory.fileExists(fileName): "file '" + fileName + "' does not exist dir=" + directory;
                if (infoStream != null)
                  message("now sync " + fileName);
                directory.sync(fileName);
                success = true;
              } finally {
                finishSync(fileName, success);
              }
            }
          }
          // All files that I require are either synced or being
          // synced by other threads.  If they are being synced,
          // we must at this point block until they are done.
          // If this returns false, that means an error in
          // another thread resulted in failing to actually
          // sync one of our files, so we repeat:
          if (waitForAllSynced(pending))
            break;
        }
        assert testPoint("midStartCommit2");
        synchronized(this) {
          // If someone saved a newer version of segments file
          // since I first started syncing my version, I can
          // safely skip saving myself since I've been
          // superseded:
          while(true) {
            if (myChangeCount <= lastCommitChangeCount) {
              if (infoStream != null) {
                message("sync superseded by newer infos");
              }
              break;
            } else if (pendingCommit == null) {
              // My turn to commit
              if (segmentInfos.getGeneration() > toSync.getGeneration())
                toSync.updateGeneration(segmentInfos);
              boolean success = false;
              try {
                // Exception here means nothing is prepared
                // (this method unwinds everything it did on
                // an exception)
                try {
                  toSync.prepareCommit(directory);
                } finally {
                  // Have our master segmentInfos record the
                  // generations we just prepared.  We do this
                  // on error or success so we don't
                  // double-write a segments_N file.
                  segmentInfos.updateGeneration(toSync);
                }
                assert pendingCommit == null;
                setPending = true;
                pendingCommit = toSync;
                pendingCommitChangeCount = myChangeCount;
                success = true;
              } finally {
                if (!success && infoStream != null)
                  message("hit exception committing segments file");
              }
              break;
            } else {
              // Must wait for other commit to complete
              doWait();
            }
          }
        }
        if (infoStream != null)
          message("done all syncs");
        assert testPoint("midStartCommitSuccess");
      } finally {
        synchronized(this) {
          if (!setPending)
            deleter.decRef(toSync);
        }
      }
    } catch (OutOfMemoryError oom) {
      handleOOM(oom, "startCommit");
    }
    assert testPoint("finishStartCommit");
  }
} 
                                                 |