| Index: CHANGES.txt |
| =================================================================== |
| --- CHANGES.txt (revision 687039) |
| +++ CHANGES.txt (working copy) |
| @@ -108,6 +108,14 @@ |
| 16. LUCENE-1334: Add new constructor for Term: Term(String fieldName) |
| which defaults term text to "". (DM Smith via Mike McCandless) |
| |
| +17. LUCENE-1329: Add optional readOnly boolean when opening an |
| + IndexReader. A readOnly reader is not allowed to make changes |
| + (deletions, norms) to the index; in exchanged, the isDeleted |
| + method, often a bottleneck when searching with many threads, is |
| + not synchronized. The default for readOnly is still false, but in |
| + 3.0 the default will become true. (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/TestIndexReader.java |
| =================================================================== |
| --- src/test/org/apache/lucene/index/TestIndexReader.java (revision 687039) |
| +++ src/test/org/apache/lucene/index/TestIndexReader.java (working copy) |
| @@ -1329,4 +1329,61 @@ |
| r2.close(); |
| d.close(); |
| } |
| + |
| + public void testReadOnly() throws Throwable { |
| + RAMDirectory d = new MockRAMDirectory(); |
| + IndexWriter writer = new IndexWriter(d, new StandardAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); |
| + addDocumentWithFields(writer); |
| + writer.commit(); |
| + addDocumentWithFields(writer); |
| + writer.close(); |
| + |
| + IndexReader r = IndexReader.open(d, true); |
| + try { |
| + r.deleteDocument(0); |
| + fail(); |
| + } catch (UnsupportedOperationException uoe) { |
| + // expected |
| + } |
| + |
| + writer = new IndexWriter(d, new StandardAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED); |
| + addDocumentWithFields(writer); |
| + writer.close(); |
| + |
| + // Make sure reopen is still readonly: |
| + IndexReader r2 = r.reopen(); |
| + r.close(); |
| + |
| + assertFalse(r == r2); |
| + |
| + try { |
| + r2.deleteDocument(0); |
| + fail(); |
| + } catch (UnsupportedOperationException uoe) { |
| + // expected |
| + } |
| + |
| + writer = new IndexWriter(d, new StandardAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED); |
| + writer.optimize(); |
| + writer.close(); |
| + |
| + // Make sure reopen to a single segment is still readonly: |
| + IndexReader r3 = r2.reopen(); |
| + r2.close(); |
| + |
| + assertFalse(r == r2); |
| + |
| + try { |
| + r3.deleteDocument(0); |
| + fail(); |
| + } catch (UnsupportedOperationException uoe) { |
| + // expected |
| + } |
| + |
| + // Make sure write lock isn't held |
| + writer = new IndexWriter(d, new StandardAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED); |
| + writer.close(); |
| + |
| + r3.close(); |
| + } |
| } |
| Index: src/java/org/apache/lucene/index/DirectoryIndexReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/DirectoryIndexReader.java (revision 687039) |
| +++ src/java/org/apache/lucene/index/DirectoryIndexReader.java (working copy) |
| @@ -43,21 +43,24 @@ |
| private SegmentInfos segmentInfos; |
| private Lock writeLock; |
| private boolean stale; |
| - private HashSet synced = new HashSet(); |
| + private final HashSet synced = new HashSet(); |
| |
| /** Used by commit() to record pre-commit state in case |
| * rollback is necessary */ |
| private boolean rollbackHasChanges; |
| private SegmentInfos rollbackSegmentInfos; |
| |
| + protected boolean readOnly; |
| + |
| |
| - void init(Directory directory, SegmentInfos segmentInfos, boolean closeDirectory) |
| + void init(Directory directory, SegmentInfos segmentInfos, boolean closeDirectory, boolean readOnly) |
| throws IOException { |
| this.directory = directory; |
| this.segmentInfos = segmentInfos; |
| this.closeDirectory = closeDirectory; |
| + this.readOnly = readOnly; |
| |
| - if (segmentInfos != null) { |
| + if (!readOnly && segmentInfos != null) { |
| // We assume that this segments_N was previously |
| // properly sync'd: |
| for(int i=0;i<segmentInfos.size();i++) { |
| @@ -72,16 +75,16 @@ |
| protected DirectoryIndexReader() {} |
| |
| DirectoryIndexReader(Directory directory, SegmentInfos segmentInfos, |
| - boolean closeDirectory) throws IOException { |
| + boolean closeDirectory, boolean readOnly) throws IOException { |
| super(); |
| - init(directory, segmentInfos, closeDirectory); |
| + init(directory, segmentInfos, closeDirectory, readOnly); |
| } |
| |
| static DirectoryIndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { |
| - return open(directory, closeDirectory, deletionPolicy, null); |
| + return open(directory, closeDirectory, deletionPolicy, null, false); |
| } |
| |
| - static DirectoryIndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit) throws CorruptIndexException, IOException { |
| + static DirectoryIndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly) throws CorruptIndexException, IOException { |
| |
| SegmentInfos.FindSegmentsFile finder = new SegmentInfos.FindSegmentsFile(directory) { |
| |
| @@ -93,9 +96,11 @@ |
| DirectoryIndexReader reader; |
| |
| if (infos.size() == 1) { // index is optimized |
| - reader = SegmentReader.get(infos, infos.info(0), closeDirectory); |
| + reader = SegmentReader.get(readOnly, infos, infos.info(0), closeDirectory); |
| + } else if (readOnly) { |
| + reader = new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory); |
| } else { |
| - reader = new MultiSegmentReader(directory, infos, closeDirectory); |
| + reader = new MultiSegmentReader(directory, infos, closeDirectory, false); |
| } |
| reader.setDeletionPolicy(deletionPolicy); |
| return reader; |
| @@ -131,7 +136,7 @@ |
| DirectoryIndexReader newReader = doReopen(infos); |
| |
| if (DirectoryIndexReader.this != newReader) { |
| - newReader.init(directory, infos, closeDirectory); |
| + newReader.init(directory, infos, closeDirectory, readOnly); |
| newReader.deletionPolicy = deletionPolicy; |
| } |
| |
| Index: src/java/org/apache/lucene/index/ReadOnlySegmentReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/ReadOnlySegmentReader.java (revision 0) |
| +++ src/java/org/apache/lucene/index/ReadOnlySegmentReader.java (revision 0) |
| @@ -0,0 +1,34 @@ |
| +package org.apache.lucene.index; |
| + |
| +/** |
| + * Licensed to the Apache Software Foundation (ASF) under one or more |
| + * contributor license agreements. See the NOTICE file distributed with |
| + * this work for additional information regarding copyright ownership. |
| + * The ASF licenses this file to You under the Apache License, Version 2.0 |
| + * (the "License"); you may not use this file except in compliance with |
| + * the License. You may obtain a copy of the License at |
| + * |
| + * http://www.apache.org/licenses/LICENSE-2.0 |
| + * |
| + * Unless required by applicable law or agreed to in writing, software |
| + * distributed under the License is distributed on an "AS IS" BASIS, |
| + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| + * See the License for the specific language governing permissions and |
| + * limitations under the License. |
| + */ |
| + |
| +class ReadOnlySegmentReader extends SegmentReader { |
| + |
| + static void noWrite() { |
| + throw new UnsupportedOperationException("This IndexReader cannot make any changes to the index (it was opened with readOnly = true)"); |
| + } |
| + |
| + protected void acquireWriteLock() { |
| + noWrite(); |
| + } |
| + |
| + // Not synchronized |
| + public boolean isDeleted(int n) { |
| + return deletedDocs != null && deletedDocs.get(n); |
| + } |
| +} |
| |
| Property changes on: src/java/org/apache/lucene/index/ReadOnlySegmentReader.java |
| ___________________________________________________________________ |
| Name: svn:eol-style |
| + native |
| |
| Index: src/java/org/apache/lucene/index/SegmentReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/SegmentReader.java (revision 687039) |
| +++ src/java/org/apache/lucene/index/SegmentReader.java (working copy) |
| @@ -61,6 +61,7 @@ |
| private boolean rollbackNormsDirty = false; |
| private boolean rollbackUndeleteAll = false; |
| private int rollbackPendingDeleteCount; |
| + private boolean readOnly; |
| |
| IndexInput freqStream; |
| IndexInput proxStream; |
| @@ -191,20 +192,46 @@ |
| } |
| } |
| |
| + private static Class READONLY_IMPL; |
| + static { |
| + try { |
| + String name = |
| + System.getProperty("org.apache.lucene.ReadOnlySegmentReader.class", |
| + ReadOnlySegmentReader.class.getName()); |
| + READONLY_IMPL = Class.forName(name); |
| + } catch (ClassNotFoundException e) { |
| + throw new RuntimeException("cannot load ReadOnlySegmentReader class: " + e, e); |
| + } catch (SecurityException se) { |
| + try { |
| + READONLY_IMPL = Class.forName(ReadOnlySegmentReader.class.getName()); |
| + } catch (ClassNotFoundException e) { |
| + throw new RuntimeException("cannot load default ReadOnlySegmentReader class: " + e, e); |
| + } |
| + } |
| + } |
| + |
| /** |
| * @throws CorruptIndexException if the index is corrupt |
| * @throws IOException if there is a low-level IO error |
| */ |
| public static SegmentReader get(SegmentInfo si) throws CorruptIndexException, IOException { |
| - return get(si.dir, si, null, false, false, BufferedIndexInput.BUFFER_SIZE, true); |
| + return get(READ_ONLY_DEFAULT, si.dir, si, null, false, false, BufferedIndexInput.BUFFER_SIZE, true); |
| } |
| |
| /** |
| * @throws CorruptIndexException if the index is corrupt |
| * @throws IOException if there is a low-level IO error |
| */ |
| + public static SegmentReader get(boolean readOnly, SegmentInfo si) throws CorruptIndexException, IOException { |
| + return get(readOnly, si.dir, si, null, false, false, BufferedIndexInput.BUFFER_SIZE, true); |
| + } |
| + |
| + /** |
| + * @throws CorruptIndexException if the index is corrupt |
| + * @throws IOException if there is a low-level IO error |
| + */ |
| static SegmentReader get(SegmentInfo si, boolean doOpenStores) throws CorruptIndexException, IOException { |
| - return get(si.dir, si, null, false, false, BufferedIndexInput.BUFFER_SIZE, doOpenStores); |
| + return get(READ_ONLY_DEFAULT, si.dir, si, null, false, false, BufferedIndexInput.BUFFER_SIZE, doOpenStores); |
| } |
| |
| /** |
| @@ -212,7 +239,7 @@ |
| * @throws IOException if there is a low-level IO error |
| */ |
| public static SegmentReader get(SegmentInfo si, int readBufferSize) throws CorruptIndexException, IOException { |
| - return get(si.dir, si, null, false, false, readBufferSize, true); |
| + return get(READ_ONLY_DEFAULT, si.dir, si, null, false, false, readBufferSize, true); |
| } |
| |
| /** |
| @@ -220,16 +247,24 @@ |
| * @throws IOException if there is a low-level IO error |
| */ |
| static SegmentReader get(SegmentInfo si, int readBufferSize, boolean doOpenStores) throws CorruptIndexException, IOException { |
| - return get(si.dir, si, null, false, false, readBufferSize, doOpenStores); |
| + return get(READ_ONLY_DEFAULT, si.dir, si, null, false, false, readBufferSize, doOpenStores); |
| } |
| |
| /** |
| * @throws CorruptIndexException if the index is corrupt |
| * @throws IOException if there is a low-level IO error |
| */ |
| - public static SegmentReader get(SegmentInfos sis, SegmentInfo si, |
| + static SegmentReader get(boolean readOnly, SegmentInfo si, int readBufferSize, boolean doOpenStores) throws CorruptIndexException, IOException { |
| + return get(readOnly, si.dir, si, null, false, false, readBufferSize, doOpenStores); |
| + } |
| + |
| + /** |
| + * @throws CorruptIndexException if the index is corrupt |
| + * @throws IOException if there is a low-level IO error |
| + */ |
| + public static SegmentReader get(boolean readOnly, SegmentInfos sis, SegmentInfo si, |
| boolean closeDir) throws CorruptIndexException, IOException { |
| - return get(si.dir, si, sis, closeDir, true, BufferedIndexInput.BUFFER_SIZE, true); |
| + return get(readOnly, si.dir, si, sis, closeDir, true, BufferedIndexInput.BUFFER_SIZE, true); |
| } |
| |
| /** |
| @@ -241,14 +276,16 @@ |
| boolean closeDir, boolean ownDir, |
| int readBufferSize) |
| throws CorruptIndexException, IOException { |
| - return get(dir, si, sis, closeDir, ownDir, readBufferSize, true); |
| + return get(READ_ONLY_DEFAULT, dir, si, sis, closeDir, ownDir, readBufferSize, true); |
| } |
| |
| /** |
| * @throws CorruptIndexException if the index is corrupt |
| * @throws IOException if there is a low-level IO error |
| */ |
| - public static SegmentReader get(Directory dir, SegmentInfo si, |
| + public static SegmentReader get(boolean readOnly, |
| + Directory dir, |
| + SegmentInfo si, |
| SegmentInfos sis, |
| boolean closeDir, boolean ownDir, |
| int readBufferSize, |
| @@ -256,11 +293,14 @@ |
| throws CorruptIndexException, IOException { |
| SegmentReader instance; |
| try { |
| - instance = (SegmentReader)IMPL.newInstance(); |
| + if (readOnly) |
| + instance = (SegmentReader)READONLY_IMPL.newInstance(); |
| + else |
| + instance = (SegmentReader)IMPL.newInstance(); |
| } catch (Exception e) { |
| throw new RuntimeException("cannot load SegmentReader class: " + e, e); |
| } |
| - instance.init(dir, sis, closeDir); |
| + instance.init(dir, sis, closeDir, readOnly); |
| instance.initialize(si, readBufferSize, doOpenStores); |
| return instance; |
| } |
| @@ -381,10 +421,13 @@ |
| } else { |
| // segment not referenced anymore, reopen not possible |
| // or segment format changed |
| - newReader = SegmentReader.get(infos, infos.info(0), false); |
| + newReader = SegmentReader.get(readOnly, infos, infos.info(0), false); |
| } |
| } else { |
| - return new MultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null); |
| + if (readOnly) |
| + return new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null); |
| + else |
| + return new MultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null, false); |
| } |
| |
| return newReader; |
| @@ -412,9 +455,15 @@ |
| |
| |
| // clone reader |
| - SegmentReader clone = new SegmentReader(); |
| + SegmentReader clone; |
| + if (readOnly) |
| + clone = new ReadOnlySegmentReader(); |
| + else |
| + clone = new SegmentReader(); |
| + |
| boolean success = false; |
| try { |
| + clone.readOnly = readOnly; |
| clone.directory = directory; |
| clone.si = si; |
| clone.segment = segment; |
| Index: src/java/org/apache/lucene/index/IndexReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/IndexReader.java (revision 687039) |
| +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) |
| @@ -45,17 +45,33 @@ |
| opened already, but it cannot be used to delete documents from the index then. |
| |
| <p> |
| - NOTE: for backwards API compatibility, several methods are not listed |
| + <b>NOTE</b>: for backwards API compatibility, several methods are not listed |
| as abstract, but have no useful implementations in this base class and |
| instead always throw UnsupportedOperationException. Subclasses are |
| strongly encouraged to override these methods, but in many cases may not |
| need to. |
| </p> |
| |
| + <p> |
| + |
| + <b>NOTE</b>: as of 2.4, it's possible to open a read-only |
| + IndexReader using one of the static open methods that |
| + accepts the boolean readOnly parameter. Such a reader has |
| + better concurrency as it's not necessary to synchronize on |
| + the isDeleted method. Currently the default for readOnly |
| + is false, meaning if not specified you will get a |
| + read/write IndexReader. But in 3.0 this default will |
| + change to true, meaning you must explicitly specify false |
| + if you want to make changes with the resulting IndexReader. |
| + </p> |
| + |
| @version $Id$ |
| */ |
| public abstract class IndexReader { |
| |
| + // NOTE: in 3.0 this will change to true |
| + final static boolean READ_ONLY_DEFAULT = false; |
| + |
| /** |
| * Constants describing field properties, for example used for |
| * {@link IndexReader#getFieldNames(FieldOption)}. |
| @@ -181,46 +197,61 @@ |
| } |
| } |
| |
| - /** Returns an IndexReader reading the index in an FSDirectory in the named |
| - path. |
| + /** Returns a read/write IndexReader reading the index in an FSDirectory in the named |
| + path. <b>NOTE</b>: starting in 3.0 this will return a readOnly IndexReader. |
| * @throws CorruptIndexException if the index is corrupt |
| * @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, null); |
| + return open(FSDirectory.getDirectory(path), true, null, null, READ_ONLY_DEFAULT); |
| } |
| |
| - /** Returns an IndexReader reading the index in an FSDirectory in the named |
| - * path. |
| + /** Returns a read/write IndexReader reading the index in an FSDirectory in the named |
| + * path. <b>NOTE</b>: starting in 3.0 this will return a readOnly IndexReader. |
| * @param path the path to the index directory |
| * @throws CorruptIndexException if the index is corrupt |
| * @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, null); |
| + return open(FSDirectory.getDirectory(path), true, null, null, READ_ONLY_DEFAULT); |
| } |
| |
| - /** Returns an IndexReader reading the index in the given Directory. |
| + /** Returns a read/write IndexReader reading the index in |
| + * the given Directory. <b>NOTE</b>: starting in 3.0 this |
| + * will return a readOnly IndexReader. |
| * @param directory the index directory |
| * @throws CorruptIndexException if the index is corrupt |
| * @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, null); |
| + return open(directory, false, null, null, READ_ONLY_DEFAULT); |
| } |
| |
| - /** Expert: returns an IndexReader reading the index in the given |
| - * {@link IndexCommit}. |
| + /** Returns a read/write or read only IndexReader reading the index in the given Directory. |
| + * @param directory the index directory |
| + * @param readOnly true if no changes (deletions, norms) will be made with this IndexReader |
| + * @throws CorruptIndexException if the index is corrupt |
| + * @throws IOException if there is a low-level IO error |
| + */ |
| + public static IndexReader open(final Directory directory, boolean readOnly) throws CorruptIndexException, IOException { |
| + return open(directory, false, null, null, readOnly); |
| + } |
| + |
| + /** Expert: returns a read/write IndexReader reading the index in the given |
| + * {@link IndexCommit}. <b>NOTE</b>: starting in 3.0 this |
| + * will return a readOnly IndexReader. |
| * @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); |
| + return open(commit.getDirectory(), false, null, commit, READ_ONLY_DEFAULT); |
| } |
| |
| - /** Expert: returns an IndexReader reading the index in the given |
| + /** Expert: returns a read/write IndexReader reading the index in the given |
| * Directory, with a custom {@link IndexDeletionPolicy}. |
| + * <b>NOTE</b>: starting in 3.0 this will return a |
| + * readOnly IndexReader. |
| * @param directory the index directory |
| * @param deletionPolicy a custom deletion policy (only used |
| * if you use this reader to perform deletes or to set |
| @@ -229,11 +260,29 @@ |
| * @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, null); |
| + return open(directory, false, deletionPolicy, null, READ_ONLY_DEFAULT); |
| } |
| |
| - /** Expert: returns an IndexReader reading the index in the given |
| - * Directory, using a specific commit and with a custom {@link IndexDeletionPolicy}. |
| + /** Expert: returns a read/write or read only IndexReader reading the index in the given |
| + * Directory, with a custom {@link IndexDeletionPolicy}. |
| + * <b>NOTE</b>: starting in 3.0 this will return a |
| + * readOnly IndexReader. |
| + * @param directory the index 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. |
| + * @param readOnly true if no changes (deletions, norms) will be made with this IndexReader |
| + * @throws CorruptIndexException if the index is corrupt |
| + * @throws IOException if there is a low-level IO error |
| + */ |
| + public static IndexReader open(final Directory directory, IndexDeletionPolicy deletionPolicy, boolean readOnly) throws CorruptIndexException, IOException { |
| + return open(directory, false, deletionPolicy, null, readOnly); |
| + } |
| + |
| + /** Expert: returns a read/write IndexReader reading the index in the given |
| + * Directory, using a specific commit and with a custom |
| + * {@link IndexDeletionPolicy}. <b>NOTE</b>: starting in |
| + * 3.0 this will return a readOnly IndexReader. |
| * @param commit the specific {@link IndexCommit} to open; |
| * see {@link IndexReader#listCommits} to list all commits |
| * in a directory |
| @@ -244,13 +293,29 @@ |
| * @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); |
| + return open(commit.getDirectory(), false, deletionPolicy, commit, READ_ONLY_DEFAULT); |
| } |
| |
| - 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); |
| + /** Expert: returns a read/write or read only 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. |
| + * @param readOnly true if no changes (deletions, norms) will be made with this IndexReader |
| + * @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, boolean readOnly) throws CorruptIndexException, IOException { |
| + return open(commit.getDirectory(), false, deletionPolicy, commit, readOnly); |
| } |
| |
| + private static IndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly) throws CorruptIndexException, IOException { |
| + return DirectoryIndexReader.open(directory, closeDirectory, deletionPolicy, commit, readOnly); |
| + } |
| + |
| /** |
| * Refreshes an IndexReader if the index has changed since this instance |
| * was (re)opened. |
| @@ -637,7 +702,7 @@ |
| * be obtained) |
| * @throws IOException if there is a low-level IO error |
| */ |
| - public final synchronized void setNorm(int doc, String field, byte value) |
| + public synchronized void setNorm(int doc, String field, byte value) |
| throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| ensureOpen(); |
| acquireWriteLock(); |
| @@ -762,7 +827,7 @@ |
| * be obtained) |
| * @throws IOException if there is a low-level IO error |
| */ |
| - public final synchronized void deleteDocument(int docNum) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| + public synchronized void deleteDocument(int docNum) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| ensureOpen(); |
| acquireWriteLock(); |
| hasChanges = true; |
| @@ -793,7 +858,7 @@ |
| * be obtained) |
| * @throws IOException if there is a low-level IO error |
| */ |
| - public final int deleteDocuments(Term term) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| + public int deleteDocuments(Term term) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| ensureOpen(); |
| TermDocs docs = termDocs(term); |
| if (docs == null) return 0; |
| @@ -819,7 +884,7 @@ |
| * @throws CorruptIndexException if the index is corrupt |
| * @throws IOException if there is a low-level IO error |
| */ |
| - public final synchronized void undeleteAll() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| + public synchronized void undeleteAll() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { |
| ensureOpen(); |
| acquireWriteLock(); |
| hasChanges = true; |
| Index: src/java/org/apache/lucene/index/MultiSegmentReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/MultiSegmentReader.java (revision 687039) |
| +++ src/java/org/apache/lucene/index/MultiSegmentReader.java (working copy) |
| @@ -42,8 +42,9 @@ |
| private boolean hasDeletions = false; |
| |
| /** Construct reading the named set of readers. */ |
| - MultiSegmentReader(Directory directory, SegmentInfos sis, boolean closeDirectory) throws IOException { |
| - super(directory, sis, closeDirectory); |
| + MultiSegmentReader(Directory directory, SegmentInfos sis, boolean closeDirectory, boolean readOnly) throws IOException { |
| + super(directory, sis, closeDirectory, readOnly); |
| + |
| // To reduce the chance of hitting FileNotFound |
| // (and having to retry), we open segments in |
| // reverse because IndexWriter merges & deletes |
| @@ -52,7 +53,7 @@ |
| SegmentReader[] readers = new SegmentReader[sis.size()]; |
| for (int i = sis.size()-1; i >= 0; i--) { |
| try { |
| - readers[i] = SegmentReader.get(sis.info(i)); |
| + readers[i] = SegmentReader.get(readOnly, sis.info(i)); |
| } catch (IOException e) { |
| // Close all readers we had opened: |
| for(i++;i<sis.size();i++) { |
| @@ -70,9 +71,9 @@ |
| } |
| |
| /** This contructor is only used for {@link #reopen()} */ |
| - MultiSegmentReader(Directory directory, SegmentInfos infos, boolean closeDirectory, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache) throws IOException { |
| - super(directory, infos, closeDirectory); |
| - |
| + MultiSegmentReader(Directory directory, SegmentInfos infos, boolean closeDirectory, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache, boolean readOnly) throws IOException { |
| + super(directory, infos, closeDirectory, readOnly); |
| + |
| // we put the old SegmentReaders in a map, that allows us |
| // to lookup a reader using its segment name |
| Map segmentReaders = new HashMap(); |
| @@ -106,7 +107,7 @@ |
| SegmentReader newReader; |
| if (newReaders[i] == null || infos.info(i).getUseCompoundFile() != newReaders[i].getSegmentInfo().getUseCompoundFile()) { |
| // this is a new reader; in case we hit an exception we can close it safely |
| - newReader = SegmentReader.get(infos.info(i)); |
| + newReader = SegmentReader.get(readOnly, infos.info(i)); |
| } else { |
| newReader = (SegmentReader) newReaders[i].reopenSegment(infos.info(i)); |
| } |
| @@ -196,11 +197,12 @@ |
| protected synchronized DirectoryIndexReader doReopen(SegmentInfos infos) throws CorruptIndexException, IOException { |
| if (infos.size() == 1) { |
| // The index has only one segment now, so we can't refresh the MultiSegmentReader. |
| - // Return a new SegmentReader instead |
| - SegmentReader newReader = SegmentReader.get(infos, infos.info(0), false); |
| - return newReader; |
| + // Return a new [ReadOnly]SegmentReader instead |
| + return SegmentReader.get(readOnly, infos, infos.info(0), false); |
| + } else if (readOnly) { |
| + return new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache); |
| } else { |
| - return new MultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache); |
| + return new MultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache, false); |
| } |
| } |
| |
| @@ -259,7 +261,7 @@ |
| |
| public boolean isDeleted(int n) { |
| // Don't call ensureOpen() here (it could affect performance) |
| - int i = readerIndex(n); // find segment num |
| + final int i = readerIndex(n); // find segment num |
| return subReaders[i].isDeleted(n - starts[i]); // dispatch to segment reader |
| } |
| |
| @@ -287,7 +289,7 @@ |
| return readerIndex(n, this.starts, this.subReaders.length); |
| } |
| |
| - static int readerIndex(int n, int[] starts, int numSubReaders) { // find reader for doc n: |
| + final static int readerIndex(int n, int[] starts, int numSubReaders) { // find reader for doc n: |
| int lo = 0; // search starts array |
| int hi = numSubReaders - 1; // for first element less |
| |
| Index: src/java/org/apache/lucene/index/IndexWriter.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/IndexWriter.java (revision 687039) |
| +++ src/java/org/apache/lucene/index/IndexWriter.java (working copy) |
| @@ -3046,7 +3046,7 @@ |
| try { |
| synchronized(this) { |
| if (segmentInfos.size() == 1){ // add existing index, if any |
| - sReader = SegmentReader.get(segmentInfos.info(0)); |
| + sReader = SegmentReader.get(true, segmentInfos.info(0)); |
| merger.add(sReader); |
| } |
| } |
| @@ -4005,7 +4005,7 @@ |
| |
| for (int i = 0; i < numSegments; i++) { |
| SegmentInfo si = sourceSegmentsClone.info(i); |
| - IndexReader reader = SegmentReader.get(si, MERGE_READ_BUFFER_SIZE, merge.mergeDocStores); // no need to set deleter (yet) |
| + IndexReader reader = SegmentReader.get(true, si, MERGE_READ_BUFFER_SIZE, merge.mergeDocStores); // no need to set deleter (yet) |
| merger.add(reader); |
| totDocCount += reader.numDocs(); |
| } |
| Index: src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java |
| =================================================================== |
| --- src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java (revision 0) |
| +++ src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java (revision 0) |
| @@ -0,0 +1,37 @@ |
| +package org.apache.lucene.index; |
| + |
| +/** |
| + * Licensed to the Apache Software Foundation (ASF) under one or more |
| + * contributor license agreements. See the NOTICE file distributed with |
| + * this work for additional information regarding copyright ownership. |
| + * The ASF licenses this file to You under the Apache License, Version 2.0 |
| + * (the "License"); you may not use this file except in compliance with |
| + * the License. You may obtain a copy of the License at |
| + * |
| + * http://www.apache.org/licenses/LICENSE-2.0 |
| + * |
| + * Unless required by applicable law or agreed to in writing, software |
| + * distributed under the License is distributed on an "AS IS" BASIS, |
| + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| + * See the License for the specific language governing permissions and |
| + * limitations under the License. |
| + */ |
| + |
| +import org.apache.lucene.store.Directory; |
| + |
| +import java.io.IOException; |
| +import java.util.Map; |
| + |
| +class ReadOnlyMultiSegmentReader extends MultiSegmentReader { |
| + ReadOnlyMultiSegmentReader(Directory directory, SegmentInfos sis, boolean closeDirectory) throws IOException { |
| + super(directory, sis, closeDirectory, true); |
| + } |
| + |
| + ReadOnlyMultiSegmentReader(Directory directory, SegmentInfos infos, boolean closeDirectory, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache) throws IOException { |
| + super(directory, infos, closeDirectory, oldReaders, oldStarts, oldNormsCache, true); |
| + } |
| + |
| + protected void acquireWriteLock() { |
| + ReadOnlySegmentReader.noWrite(); |
| + } |
| +} |
| |
| Property changes on: src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java |
| ___________________________________________________________________ |
| Name: svn:eol-style |
| + native |
| |