/** * Expunges the deleted documents. * Compacts and merges all segments containing deleted documents. * @throws IOException */ public final void expungeDeleted() throws IOException { final Vector segmentsToDelete = new Vector(); final SegmentInfos newInfos = new SegmentInfos(); if (infoStream != null) { infoStream.print("Expunging deleted documents."); } // iterate thru all the segment infos for (int i = 0; i < segmentInfos.size(); i++) { SegmentInfo si = segmentInfos.info(i); Directory directory = si.dir; if (SegmentReader.hasDeletions(si)) { // found a deletion // make a new segment and merge itself String newSegment = newSegmentName(); SegmentReader reader = SegmentReader.get(si); SegmentMerger merger = new SegmentMerger(directory, newSegment); merger.add(reader); int newDocCount = merger.merge(); merger.closeReaders(); // do the compound file thing if (useCompoundFile) { final Vector filesToDelete = merger .createCompoundFile(newSegment + ".tmp"); synchronized (directory) { // in- & inter-process sync boolean locked = false; Lock lock = directory.makeLock(COMMIT_LOCK_NAME); try { locked = lock.obtain(COMMIT_LOCK_TIMEOUT); // make compound file visible for SegmentReaders directory.renameFile(newSegment + ".tmp", newSegment + ".cfs"); // delete now unused files of segment deleteFiles(filesToDelete); } finally { if (locked) lock.release(); } } } if ((reader.directory() == this.directory) || // if we own the // directory (reader.directory() == this.ramDirectory)) { segmentsToDelete.add(reader); } newInfos .add(new SegmentInfo(newSegment, newDocCount, directory)); } else { newInfos.add(si); } } // rewrite the segment info if there is something changed if (segmentsToDelete.size() > 0) { synchronized (directory) { // in- & inter-process sync new Lock.With(directory.makeLock(COMMIT_LOCK_NAME), COMMIT_LOCK_TIMEOUT) { public Object doBody() throws IOException { newInfos.write(directory); // commit before deleting deleteSegments(segmentsToDelete); // delete now-unused // segments return null; } }.run(); } } }