| Index: CHANGES.txt |
| =================================================================== |
| --- CHANGES.txt (revision 669847) |
| +++ CHANGES.txt (working copy) |
| @@ -76,6 +76,13 @@ |
| returns when the reader is opened on the same commit. (Jason |
| Rutherglen via Mike McCandless) |
| |
| +11. LUCENE-1311: Added IndexReader.listCommits(Directory) static |
| + method to list all commits in a Directory, plus IndexReader.open |
| + methods that accept an IndexCommit and open the index as of that |
| + commit. These methods are only useful if you implement a custom |
| + DeletionPolicy that keeps more than the last commit around. |
| + (Jason Rutherglen via Mike McCandless) |
| + |
| Bug fixes |
| |
| 1. LUCENE-1134: Fixed BooleanQuery.rewrite to only optimize a single |
| Index: src/test/org/apache/lucene/index/TestDeletionPolicy.java |
| =================================================================== |
| --- src/test/org/apache/lucene/index/TestDeletionPolicy.java (revision 669847) |
| +++ src/test/org/apache/lucene/index/TestDeletionPolicy.java (working copy) |
| @@ -22,6 +22,7 @@ |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| +import java.util.Collection; |
| |
| import org.apache.lucene.analysis.WhitespaceAnalyzer; |
| import org.apache.lucene.document.Document; |
| @@ -258,6 +259,7 @@ |
| boolean autoCommit = pass < 2; |
| boolean useCompoundFile = (pass % 2) > 0; |
| |
| + // Never deletes a commit |
| KeepAllDeletionPolicy policy = new KeepAllDeletionPolicy(); |
| |
| Directory dir = new RAMDirectory(); |
| @@ -267,6 +269,8 @@ |
| writer.setUseCompoundFile(useCompoundFile); |
| for(int i=0;i<107;i++) { |
| addDoc(writer); |
| + if (autoCommit && i%10 == 0) |
| + writer.commit(); |
| } |
| writer.close(); |
| |
| @@ -281,6 +285,24 @@ |
| // be exactly 2 commits (one per close above): |
| assertEquals(2, policy.numOnCommit); |
| |
| + // Test listCommits |
| + Collection commits = IndexReader.listCommits(dir); |
| + if (!autoCommit) |
| + // 1 from opening writer + 2 from closing writer |
| + assertEquals(3, commits.size()); |
| + else |
| + // 1 from opening writer + 2 from closing writer + |
| + // 11 from calling writer.commit() explicitly above |
| + assertEquals(14, commits.size()); |
| + |
| + Iterator it = commits.iterator(); |
| + // Make sure we can open a reader on each commit: |
| + while(it.hasNext()) { |
| + IndexCommit commit = (IndexCommit) it.next(); |
| + IndexReader r = IndexReader.open(commit, null); |
| + r.close(); |
| + } |
| + |
| // Simplistic check: just verify all segments_N's still |
| // exist, and, I can open a reader on each: |
| dir.deleteFile(IndexFileNames.SEGMENTS_GEN); |
| Index: src/java/org/apache/lucene/index/DirectoryIndexReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/DirectoryIndexReader.java (revision 669847) |
| +++ src/java/org/apache/lucene/index/DirectoryIndexReader.java (working copy) |
| @@ -18,6 +18,7 @@ |
| */ |
| |
| import java.io.IOException; |
| +import java.io.FileNotFoundException; |
| |
| import java.util.HashSet; |
| import java.util.Collection; |
| @@ -77,9 +78,13 @@ |
| } |
| |
| static DirectoryIndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { |
| + return open(directory, closeDirectory, deletionPolicy, null); |
| + } |
| |
| - return (DirectoryIndexReader) new SegmentInfos.FindSegmentsFile(directory) { |
| + static DirectoryIndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit) throws CorruptIndexException, IOException { |
| |
| + SegmentInfos.FindSegmentsFile finder = new SegmentInfos.FindSegmentsFile(directory) { |
| + |
| protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException { |
| |
| SegmentInfos infos = new SegmentInfos(); |
| @@ -95,7 +100,17 @@ |
| reader.setDeletionPolicy(deletionPolicy); |
| return reader; |
| } |
| - }.run(); |
| + }; |
| + |
| + if (commit == null) |
| + return (DirectoryIndexReader) finder.run(); |
| + else { |
| + if (directory != commit.getDirectory()) |
| + throw new IOException("the specified commit does not match the specified Directory"); |
| + // This can & will directly throw IOException if the |
| + // specified commit point has been deleted: |
| + return (DirectoryIndexReader) finder.doBody(commit.getSegmentsFileName()); |
| + } |
| } |
| |
| public final synchronized IndexReader reopen() throws CorruptIndexException, IOException { |
| @@ -192,7 +207,7 @@ |
| * @throws IOException if there is a low-level IO error |
| */ |
| protected void doCommit() throws IOException { |
| - if(hasChanges){ |
| + if (hasChanges) { |
| if (segmentInfos != null) { |
| |
| // Default deleter (for backwards compatibility) is |
| @@ -387,4 +402,51 @@ |
| public IndexCommit getIndexCommit() throws IOException { |
| return new ReaderCommit(segmentInfos, directory); |
| } |
| + |
| + /** @see IndexReader#listCommits */ |
| + public static Collection listCommits(Directory dir) throws IOException { |
| + |
| + final String[] files = dir.list(); |
| + if (files == null) |
| + throw new IOException("cannot read directory " + dir + ": list() returned null"); |
| + |
| + Collection commits = new ArrayList(); |
| + |
| + SegmentInfos latest = new SegmentInfos(); |
| + latest.read(dir); |
| + final long currentGen = latest.getGeneration(); |
| + |
| + commits.add(new ReaderCommit(latest, dir)); |
| + |
| + for(int i=0;i<files.length;i++) { |
| + |
| + final String fileName = files[i]; |
| + |
| + if (fileName.startsWith(IndexFileNames.SEGMENTS) && |
| + !fileName.equals(IndexFileNames.SEGMENTS_GEN) && |
| + SegmentInfos.generationFromSegmentsFileName(fileName) < currentGen) { |
| + |
| + SegmentInfos sis = new SegmentInfos(); |
| + try { |
| + // IOException allowed to throw there, in case |
| + // segments_N is corrupt |
| + sis.read(dir, fileName); |
| + } catch (FileNotFoundException fnfe) { |
| + // LUCENE-948: on NFS (and maybe others), if |
| + // you have writers switching back and forth |
| + // between machines, it's very likely that the |
| + // dir listing will be stale and will claim a |
| + // file segments_X exists when in fact it |
| + // doesn't. So, we catch this and handle it |
| + // as if the file does not exist |
| + sis = null; |
| + } |
| + |
| + if (sis != null) |
| + commits.add(new ReaderCommit(sis, dir)); |
| + } |
| + } |
| + |
| + return commits; |
| + } |
| } |
| Index: src/java/org/apache/lucene/index/IndexCommit.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/IndexCommit.java (revision 669847) |
| +++ src/java/org/apache/lucene/index/IndexCommit.java (working copy) |
| @@ -75,8 +75,7 @@ |
| } |
| |
| /** |
| - * Two IndexCommits are equal if both their Directory and |
| - * segmentsFileName are equal. |
| + * Two IndexCommits are equal if both their Directory and versions are equal. |
| */ |
| public boolean equals(Object other) { |
| if (other instanceof IndexCommit) { |
| Index: src/java/org/apache/lucene/index/IndexReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/IndexReader.java (revision 669847) |
| +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) |
| @@ -170,7 +170,7 @@ |
| * @throws IOException if there is a low-level IO error |
| * @param path the path to the index directory */ |
| public static IndexReader open(String path) throws CorruptIndexException, IOException { |
| - return open(FSDirectory.getDirectory(path), true, null); |
| + return open(FSDirectory.getDirectory(path), true, null, null); |
| } |
| |
| /** Returns an IndexReader reading the index in an FSDirectory in the named |
| @@ -180,7 +180,7 @@ |
| * @throws IOException if there is a low-level IO error |
| */ |
| public static IndexReader open(File path) throws CorruptIndexException, IOException { |
| - return open(FSDirectory.getDirectory(path), true, null); |
| + return open(FSDirectory.getDirectory(path), true, null, null); |
| } |
| |
| /** Returns an IndexReader reading the index in the given Directory. |
| @@ -189,10 +189,20 @@ |
| * @throws IOException if there is a low-level IO error |
| */ |
| public static IndexReader open(final Directory directory) throws CorruptIndexException, IOException { |
| - return open(directory, false, null); |
| + return open(directory, false, null, null); |
| } |
| |
| /** Expert: returns an IndexReader reading the index in the given |
| + * {@link IndexCommit}. |
| + * @param commit the commit point to open |
| + * @throws CorruptIndexException if the index is corrupt |
| + * @throws IOException if there is a low-level IO error |
| + */ |
| + public static IndexReader open(final IndexCommit commit) throws CorruptIndexException, IOException { |
| + return open(commit.getDirectory(), false, null, commit); |
| + } |
| + |
| + /** Expert: returns an IndexReader reading the index in the given |
| * Directory, with a custom {@link IndexDeletionPolicy}. |
| * @param directory the index directory |
| * @param deletionPolicy a custom deletion policy (only used |
| @@ -202,13 +212,28 @@ |
| * @throws IOException if there is a low-level IO error |
| */ |
| public static IndexReader open(final Directory directory, IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { |
| - return open(directory, false, deletionPolicy); |
| + return open(directory, false, deletionPolicy, null); |
| } |
| |
| - private static IndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { |
| - return DirectoryIndexReader.open(directory, closeDirectory, deletionPolicy); |
| + /** Expert: returns an IndexReader reading the index in the given |
| + * Directory, using a specific commit and with a custom {@link IndexDeletionPolicy}. |
| + * @param commit the specific {@link IndexCommit} to open; |
| + * see {@link IndexReader#listCommits} to list all commits |
| + * in a directory |
| + * @param deletionPolicy a custom deletion policy (only used |
| + * if you use this reader to perform deletes or to set |
| + * norms); see {@link IndexWriter} for details. |
| + * @throws CorruptIndexException if the index is corrupt |
| + * @throws IOException if there is a low-level IO error |
| + */ |
| + public static IndexReader open(final IndexCommit commit, IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { |
| + return open(commit.getDirectory(), false, deletionPolicy, commit); |
| } |
| |
| + private static IndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit) throws CorruptIndexException, IOException { |
| + return DirectoryIndexReader.open(directory, closeDirectory, deletionPolicy, commit); |
| + } |
| + |
| /** |
| * Refreshes an IndexReader if the index has changed since this instance |
| * was (re)opened. |
| @@ -975,4 +1000,20 @@ |
| } |
| } |
| } |
| + |
| + /** Returns all commit points that exist in the Directory. |
| + * Normally, because the default is {@link |
| + * KeepOnlyLastCommitDeletionPolicy}, there would be only |
| + * one commit point. But if you're using a custom {@link |
| + * DeletionPolicy} then there could be many commits. |
| + * Once you have a given commit, you can open a reader on |
| + * it by calling {@link IndexReader#open(Directory, |
| + * IndexCommit)}. There must be at least one commit in |
| + * the Directory, else this method throws {@link |
| + * java.io.IOException}. Note that if a commit is in |
| + * progress while this method is running, that commit |
| + * may or may not be returned array. */ |
| + public static Collection listCommits(Directory dir) throws IOException { |
| + return DirectoryIndexReader.listCommits(dir); |
| + } |
| } |