lucene-java-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mikemcc...@apache.org
Subject svn commit: r688323 - in /lucene/java/trunk: ./ src/java/org/apache/lucene/index/ src/test/org/apache/lucene/index/
Date Sat, 23 Aug 2008 13:47:19 GMT
Author: mikemccand
Date: Sat Aug 23 06:47:18 2008
New Revision: 688323

URL: http://svn.apache.org/viewvc?rev=688323&view=rev
Log:
LUCENE-1329: enable read-only IndexReaders; the default is to get a read-write IndexReader
on open, but in 3.0 this will change to read-only

Added:
    lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java   (with
props)
    lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java   (with
props)
Modified:
    lucene/java/trunk/CHANGES.txt
    lucene/java/trunk/src/java/org/apache/lucene/index/DirectoryIndexReader.java
    lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java
    lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java
    lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java
    lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java
    lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java

Modified: lucene/java/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/trunk/CHANGES.txt?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/CHANGES.txt (original)
+++ lucene/java/trunk/CHANGES.txt Sat Aug 23 06:47:18 2008
@@ -114,6 +114,14 @@
     hashCode() and equals() in Token, and fixed all core and contrib
     analyzers to use the re-use APIs.  (DM Smith via Mike McCandless)
 
+18. 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 

Modified: lucene/java/trunk/src/java/org/apache/lucene/index/DirectoryIndexReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/DirectoryIndexReader.java?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/DirectoryIndexReader.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/DirectoryIndexReader.java Sat Aug 23
06:47:18 2008
@@ -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;
         }
 

Modified: lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java Sat Aug 23 06:47:18
2008
@@ -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,11 +293,27 @@
    * @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);
+  }
+
+  /** 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) throws CorruptIndexException,
IOException {
-    return DirectoryIndexReader.open(directory, closeDirectory, deletionPolicy, commit);
+  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);
   }
 
   /**
@@ -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;

Modified: lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java Sat Aug 23 06:47:18
2008
@@ -3015,7 +3015,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);
           }
         }
@@ -3974,7 +3974,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();
       }

Modified: lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java Sat Aug 23
06:47:18 2008
@@ -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
 

Added: lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java?rev=688323&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java Sat
Aug 23 06:47:18 2008
@@ -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();
+  }
+}

Propchange: lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlyMultiSegmentReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java?rev=688323&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java Sat Aug
23 06:47:18 2008
@@ -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);
+  }
+}

Propchange: lucene/java/trunk/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java Sat Aug 23 06:47:18
2008
@@ -61,6 +61,7 @@
   private boolean rollbackNormsDirty = false;
   private boolean rollbackUndeleteAll = false;
   private int rollbackPendingDeleteCount;
+  private boolean readOnly;
 
   IndexInput freqStream;
   IndexInput proxStream;
@@ -191,12 +192,38 @@
     }
   }
 
+  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);
   }
 
   /**
@@ -204,7 +231,7 @@
    * @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
+   */
+  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(SegmentInfos sis, SegmentInfo si,
+  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;

Modified: lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java?rev=688323&r1=688322&r2=688323&view=diff
==============================================================================
--- lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java (original)
+++ lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java Sat Aug 23 06:47:18
2008
@@ -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();
+    }
 }



Mime
View raw message