FileDocCategorySizeDatePackage
IndexFileDeleter.javaAPI DocApache Lucene 2.1.09942Wed Feb 14 10:46:40 GMT 2007org.apache.lucene.index

IndexFileDeleter

public final class IndexFileDeleter extends Object
A utility class (used by both IndexReader and IndexWriter) to keep track of files that need to be deleted because they are no longer referenced by the index.

Fields Summary
private Vector
deletable
private HashSet
pending
private Directory
directory
private SegmentInfos
segmentInfos
private PrintStream
infoStream
Constructors Summary
IndexFileDeleter(SegmentInfos segmentInfos, Directory directory)

    this.segmentInfos = segmentInfos;
    this.directory = directory;
  
Methods Summary
voidaddDeletableFile(java.lang.String fileName)

    if (deletable == null) {
      deletable = new Vector();
    }
    deletable.addElement(fileName);
  
voidaddPendingFile(java.lang.String fileName)

    if (pending == null) {
      pending = new HashSet();
    }
    pending.add(fileName);
  
voidaddPendingFiles(java.util.Vector files)

    for(int i=0;i<files.size();i++) {
      addPendingFile((String) files.elementAt(i));
    }
  
voidaddPendingSegments(java.util.Vector segments)

    for (int i = 0; i < segments.size(); i++) {
      SegmentReader reader = (SegmentReader)segments.elementAt(i);
      if (reader.directory() == this.directory) {
        addPendingFiles(reader.files());
      }
    }
  
voidclearPendingFiles()

    pending = null;
  
voidcommitPendingFiles()

    if (pending != null) {
      if (deletable == null) {
        deletable = new Vector();
      }
      Iterator it = pending.iterator();
      while(it.hasNext()) {
        deletable.addElement(it.next());
      }
      pending = null;
      deleteFiles();
    }
  
voiddeleteFile(java.lang.String file)

    try {
      directory.deleteFile(file);		  // try to delete each file
    } catch (IOException e) {			  // if delete fails
      if (directory.fileExists(file)) {
        if (infoStream != null)
          infoStream.println("IndexFileDeleter: unable to remove file \"" + file + "\": " + e.toString() + "; Will re-try later.");
        addDeletableFile(file);                  // add to deletable
      }
    }
  
voiddeleteFiles()

    if (deletable != null) {
      Vector oldDeletable = deletable;
      deletable = null;
      deleteFiles(oldDeletable); // try to delete deletable
    }
  
voiddeleteFiles(java.util.Vector files, org.apache.lucene.store.Directory directory)

    for (int i = 0; i < files.size(); i++)
      directory.deleteFile((String)files.elementAt(i));
  
voiddeleteFiles(java.util.Vector files)

    deleteFiles();                                // try to delete files that we couldn't before
    for (int i = 0; i < files.size(); i++) {
      deleteFile((String) files.elementAt(i));
    }
  
voiddeleteSegments(java.util.Vector segments)


    deleteFiles();                                // try to delete files that we couldn't before

    for (int i = 0; i < segments.size(); i++) {
      SegmentReader reader = (SegmentReader)segments.elementAt(i);
      if (reader.directory() == this.directory)
        deleteFiles(reader.files()); // try to delete our files
      else
        deleteFiles(reader.files(), reader.directory()); // delete other files
    }
  
voiddeleteSegments(java.util.Vector segments, java.util.HashSet protectedSegments)
Delete these segments, as long as they are not listed in protectedSegments. If they are, then, instead, add them to the pending set.


    deleteFiles();                                // try to delete files that we couldn't before

    for (int i = 0; i < segments.size(); i++) {
      SegmentReader reader = (SegmentReader)segments.elementAt(i);
      if (reader.directory() == this.directory) {
        if (protectedSegments.contains(reader.getSegmentName())) {
          addPendingFiles(reader.files()); // record these for deletion on commit
        } else {
          deleteFiles(reader.files()); // try to delete our files
        }
      }  else {
        deleteFiles(reader.files(), reader.directory()); // delete other files
      }
    }
  
voidfindDeletableFiles()
Determine index files that are no longer referenced and therefore should be deleted. This is called once (by the writer), and then subsequently we add onto deletable any files that are no longer needed at the point that we create the unused file (eg when merging segments), and we only remove from deletable when a file is successfully deleted.


    // Gather all "current" segments:
    HashMap current = new HashMap();
    for(int j=0;j<segmentInfos.size();j++) {
      SegmentInfo segmentInfo = (SegmentInfo) segmentInfos.elementAt(j);
      current.put(segmentInfo.name, segmentInfo);
    }

    // Then go through all files in the Directory that are
    // Lucene index files, and add to deletable if they are
    // not referenced by the current segments info:

    String segmentsInfosFileName = segmentInfos.getCurrentSegmentFileName();
    IndexFileNameFilter filter = IndexFileNameFilter.getFilter();

    String[] files = directory.list();

    for (int i = 0; i < files.length; i++) {

      if (filter.accept(null, files[i]) && !files[i].equals(segmentsInfosFileName) && !files[i].equals(IndexFileNames.SEGMENTS_GEN)) {

        String segmentName;
        String extension;

        // First remove any extension:
        int loc = files[i].indexOf('.");
        if (loc != -1) {
          extension = files[i].substring(1+loc);
          segmentName = files[i].substring(0, loc);
        } else {
          extension = null;
          segmentName = files[i];
        }

        // Then, remove any generation count:
        loc = segmentName.indexOf('_", 1);
        if (loc != -1) {
          segmentName = segmentName.substring(0, loc);
        }

        // Delete this file if it's not a "current" segment,
        // or, it is a single index file but there is now a
        // corresponding compound file:
        boolean doDelete = false;

        if (!current.containsKey(segmentName)) {
          // Delete if segment is not referenced:
          doDelete = true;
        } else {
          // OK, segment is referenced, but file may still
          // be orphan'd:
          SegmentInfo info = (SegmentInfo) current.get(segmentName);

          if (filter.isCFSFile(files[i]) && info.getUseCompoundFile()) {
            // This file is in fact stored in a CFS file for
            // this segment:
            doDelete = true;
          } else {
            
            if ("del".equals(extension)) {
              // This is a _segmentName_N.del file:
              if (!files[i].equals(info.getDelFileName())) {
                // If this is a seperate .del file, but it
                // doesn't match the current del filename for
                // this segment, then delete it:
                doDelete = true;
              }
            } else if (extension != null && extension.startsWith("s") && extension.matches("s\\d+")) {
              int field = Integer.parseInt(extension.substring(1));
              // This is a _segmentName_N.sX file:
              if (!files[i].equals(info.getNormFileName(field))) {
                // This is an orphan'd separate norms file:
                doDelete = true;
              }
            } else if ("cfs".equals(extension) && !info.getUseCompoundFile()) {
              // This is a partially written
              // _segmentName.cfs:
              doDelete = true;
            }
          }
        }

        if (doDelete) {
          addDeletableFile(files[i]);
          if (infoStream != null) {
            infoStream.println("IndexFileDeleter: file \"" + files[i] + "\" is unreferenced in index and will be deleted on next commit");
          }
        }
      }
    }
  
org.apache.lucene.index.SegmentInfosgetSegmentInfos()

    return segmentInfos;
  
voidsetInfoStream(java.io.PrintStream infoStream)

    this.infoStream = infoStream;
  
voidsetSegmentInfos(org.apache.lucene.index.SegmentInfos segmentInfos)

    this.segmentInfos = segmentInfos;