LUCENE-3606: Some final cleanups in SegmentReader, all RW methods are now at the end of class file, so all at one place. No public write access anymore.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene3606@1212007 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lucene/src/java/org/apache/lucene/index/DirectoryReader.java b/lucene/src/java/org/apache/lucene/index/DirectoryReader.java
index 6e5db7f..0b94468 100644
--- a/lucene/src/java/org/apache/lucene/index/DirectoryReader.java
+++ b/lucene/src/java/org/apache/lucene/index/DirectoryReader.java
@@ -211,7 +211,7 @@
           readerShared[i] = false;
           newReaders[i] = newReader;
         } else {
-          newReader = newReaders[i].reopenSegment(infos.info(i), doClone, true);
+          newReader = newReaders[i].reopenSegment(infos.info(i), doClone);
           if (newReader == null) {
             // this reader will be shared between the old and the new one,
             // so we must incRef it
diff --git a/lucene/src/java/org/apache/lucene/index/SegmentReader.java b/lucene/src/java/org/apache/lucene/index/SegmentReader.java
index 5e6c6fd..f94fa0d 100644
--- a/lucene/src/java/org/apache/lucene/index/SegmentReader.java
+++ b/lucene/src/java/org/apache/lucene/index/SegmentReader.java
@@ -161,17 +161,6 @@
     } else
       assert si.getDelCount() == 0;
   }
-  
-  /**
-   * Clones the deleteDocs BitVector.  May be overridden by subclasses. New and experimental.
-   * @param bv BitVector to clone
-   * @return New BitVector
-   */
-  // TODO: remove deletions from SR
-  BitVector cloneDeletedDocs(BitVector bv) {
-    ensureOpen();
-    return (BitVector)bv.clone();
-  }
 
   @Override
   public final synchronized Object clone() {
@@ -182,144 +171,16 @@
     }
   }
 
-  // TODO: is this needed anymore by IndexWriter?
-  final synchronized IndexReader clone(boolean openReadOnly) throws CorruptIndexException, IOException {
-    return reopenSegment(si, true, openReadOnly);
+  // used by DirectoryReader:
+  synchronized SegmentReader reopenSegment(SegmentInfo si, boolean doClone) throws CorruptIndexException, IOException {
+    return reopenSegment(si, doClone, true);
   }
 
   @Override
   protected synchronized IndexReader doOpenIfChanged() throws CorruptIndexException, IOException {
     return reopenSegment(si, false, readOnly);
   }
-
-  synchronized SegmentReader reopenSegment(SegmentInfo si, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException {
-    ensureOpen();
-    boolean deletionsUpToDate = (this.si.hasDeletions() == si.hasDeletions()) 
-                                  && (!si.hasDeletions() || this.si.getDelFileName().equals(si.getDelFileName()));
-
-    // if we're cloning we need to run through the reopenSegment logic
-    // also if both old and new readers aren't readonly, we clone to avoid sharing modifications
-    if (deletionsUpToDate && !doClone && openReadOnly && readOnly) {
-      return null;
-    }    
-
-    // When cloning, the incoming SegmentInfos should not
-    // have any changes in it:
-    assert !doClone || (deletionsUpToDate);
-
-    // clone reader
-    SegmentReader clone = new SegmentReader(openReadOnly, si);
-
-    boolean success = false;
-    try {
-      core.incRef();
-      clone.core = core;
-      clone.pendingDeleteCount = pendingDeleteCount;
-      clone.readerFinishedListeners = readerFinishedListeners;
-
-      if (!openReadOnly && hasChanges) {
-        // My pending changes transfer to the new reader
-        clone.liveDocsDirty = liveDocsDirty;
-        clone.hasChanges = hasChanges;
-        hasChanges = false;
-      }
-      
-      if (doClone) {
-        if (liveDocs != null) {
-          liveDocsRef.incrementAndGet();
-          clone.liveDocs = liveDocs;
-          clone.liveDocsRef = liveDocsRef;
-        }
-      } else {
-        if (!deletionsUpToDate) {
-          // load deleted docs
-          assert clone.liveDocs == null;
-          clone.loadLiveDocs(IOContext.READ);
-        } else if (liveDocs != null) {
-          liveDocsRef.incrementAndGet();
-          clone.liveDocs = liveDocs;
-          clone.liveDocsRef = liveDocsRef;
-        }
-      }
-      success = true;
-    } finally {
-      if (!success) {
-        // An exception occurred during reopen, we have to decRef the norms
-        // that we incRef'ed already and close singleNormsStream and FieldsReader
-        clone.decRef();
-      }
-    }
-    
-    return clone;
-  }
-
-  // TODO: remove deletions from SR
-  void doCommit() throws IOException {
-    assert hasChanges;
-    startCommit();
-    boolean success = false;
-    try {
-      commitChanges();
-      success = true;
-    } finally {
-      if (!success) {
-        rollbackCommit();
-      }
-    }
-  }
-
-  // TODO: remove deletions from SR
-  private void startCommit() {
-    rollbackSegmentInfo = (SegmentInfo) si.clone();
-    rollbackHasChanges = hasChanges;
-    rollbackDeletedDocsDirty = liveDocsDirty;
-    rollbackPendingDeleteCount = pendingDeleteCount;
-  }
-
-  // TODO: remove deletions from SR
-  private void rollbackCommit() {
-    si.reset(rollbackSegmentInfo);
-    hasChanges = rollbackHasChanges;
-    liveDocsDirty = rollbackDeletedDocsDirty;
-    pendingDeleteCount = rollbackPendingDeleteCount;
-  }
-
-  // TODO: remove deletions from SR
-  private synchronized void commitChanges() throws IOException {
-    if (liveDocsDirty) {               // re-write deleted
-      si.advanceDelGen();
-
-      assert liveDocs.length() == si.docCount;
-
-      // We can write directly to the actual name (vs to a
-      // .tmp & renaming it) because the file is not live
-      // until segments file is written:
-      final String delFileName = si.getDelFileName();
-      boolean success = false;
-      try {
-        liveDocs.write(directory(), delFileName, IOContext.DEFAULT);
-        success = true;
-      } finally {
-        if (!success) {
-          try {
-            directory().deleteFile(delFileName);
-          } catch (Throwable t) {
-            // suppress this so we keep throwing the
-            // original exception
-          }
-        }
-      }
-      si.setDelCount(si.getDelCount()+pendingDeleteCount);
-      pendingDeleteCount = 0;
-      assert (maxDoc()-liveDocs.count()) == si.getDelCount(): "delete count mismatch during commit: info=" + si.getDelCount() + " vs BitVector=" + (maxDoc()-liveDocs.count());
-    } else {
-      assert pendingDeleteCount == 0;
-    }
-
-    liveDocsDirty = false;
-    hasChanges = false;
-  }
-
+  
   /** @lucene.internal */
   public StoredFieldsReader getFieldsReader() {
     return fieldsReaderLocal.get();
@@ -351,35 +212,6 @@
     return liveDocs != null;
   }
 
-  // TODO: remove deletions from SR
-  synchronized void deleteDocument(int docNum) throws IOException {
-    ensureOpen();
-    hasChanges = true;
-    doDelete(docNum);
-  }
-
-  // TODO: remove deletions from SR
-  void doDelete(int docNum) {
-    if (liveDocs == null) {
-      liveDocs = new BitVector(maxDoc());
-      liveDocs.setAll();
-      liveDocsRef = new AtomicInteger(1);
-    }
-    // there is more than 1 SegmentReader with a reference to this
-    // liveDocs BitVector so decRef the current liveDocsRef,
-    // clone the BitVector, create a new liveDocsRef
-    if (liveDocsRef.get() > 1) {
-      AtomicInteger oldRef = liveDocsRef;
-      liveDocs = cloneDeletedDocs(liveDocs);
-      liveDocsRef = new AtomicInteger(1);
-      oldRef.decrementAndGet();
-    }
-    liveDocsDirty = true;
-    if (liveDocs.getAndClear(docNum)) {
-      pendingDeleteCount++;
-    }
-  }
-
   List<String> files() throws IOException {
     return new ArrayList<String>(si.files());
   }
@@ -526,7 +358,6 @@
     return termVectorsReader.get(docID);
   }
 
-  /** {@inheritDoc} */
   @Override
   public String toString() {
     final StringBuilder buffer = new StringBuilder();
@@ -598,4 +429,178 @@
     ensureOpen();
     return core.perDocProducer;
   }
+
+  /**
+   * Clones the deleteDocs BitVector.  May be overridden by subclasses. New and experimental.
+   * @param bv BitVector to clone
+   * @return New BitVector
+   */
+  // TODO: remove deletions from SR
+  BitVector cloneDeletedDocs(BitVector bv) {
+    ensureOpen();
+    return (BitVector)bv.clone();
+  }
+  
+  // TODO: remove deletions from SR
+  final synchronized IndexReader clone(boolean openReadOnly) throws CorruptIndexException, IOException {
+    return reopenSegment(si, true, openReadOnly);
+  }
+
+  // TODO: remove deletions from SR
+  private synchronized SegmentReader reopenSegment(SegmentInfo si, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException {
+    ensureOpen();
+    boolean deletionsUpToDate = (this.si.hasDeletions() == si.hasDeletions()) 
+                                  && (!si.hasDeletions() || this.si.getDelFileName().equals(si.getDelFileName()));
+
+    // if we're cloning we need to run through the reopenSegment logic
+    // also if both old and new readers aren't readonly, we clone to avoid sharing modifications
+    if (deletionsUpToDate && !doClone && openReadOnly && readOnly) {
+      return null;
+    }    
+
+    // When cloning, the incoming SegmentInfos should not
+    // have any changes in it:
+    assert !doClone || (deletionsUpToDate);
+
+    // clone reader
+    SegmentReader clone = new SegmentReader(openReadOnly, si);
+
+    boolean success = false;
+    try {
+      core.incRef();
+      clone.core = core;
+      clone.pendingDeleteCount = pendingDeleteCount;
+      clone.readerFinishedListeners = readerFinishedListeners;
+
+      if (!openReadOnly && hasChanges) {
+        // My pending changes transfer to the new reader
+        clone.liveDocsDirty = liveDocsDirty;
+        clone.hasChanges = hasChanges;
+        hasChanges = false;
+      }
+      
+      if (doClone) {
+        if (liveDocs != null) {
+          liveDocsRef.incrementAndGet();
+          clone.liveDocs = liveDocs;
+          clone.liveDocsRef = liveDocsRef;
+        }
+      } else {
+        if (!deletionsUpToDate) {
+          // load deleted docs
+          assert clone.liveDocs == null;
+          clone.loadLiveDocs(IOContext.READ);
+        } else if (liveDocs != null) {
+          liveDocsRef.incrementAndGet();
+          clone.liveDocs = liveDocs;
+          clone.liveDocsRef = liveDocsRef;
+        }
+      }
+      success = true;
+    } finally {
+      if (!success) {
+        // An exception occurred during reopen, we have to decRef the norms
+        // that we incRef'ed already and close singleNormsStream and FieldsReader
+        clone.decRef();
+      }
+    }
+    
+    return clone;
+  }
+
+  // TODO: remove deletions from SR
+  void doCommit() throws IOException {
+    assert hasChanges;
+    startCommit();
+    boolean success = false;
+    try {
+      commitChanges();
+      success = true;
+    } finally {
+      if (!success) {
+        rollbackCommit();
+      }
+    }
+  }
+
+  // TODO: remove deletions from SR
+  private void startCommit() {
+    rollbackSegmentInfo = (SegmentInfo) si.clone();
+    rollbackHasChanges = hasChanges;
+    rollbackDeletedDocsDirty = liveDocsDirty;
+    rollbackPendingDeleteCount = pendingDeleteCount;
+  }
+
+  // TODO: remove deletions from SR
+  private void rollbackCommit() {
+    si.reset(rollbackSegmentInfo);
+    hasChanges = rollbackHasChanges;
+    liveDocsDirty = rollbackDeletedDocsDirty;
+    pendingDeleteCount = rollbackPendingDeleteCount;
+  }
+
+  // TODO: remove deletions from SR
+  private synchronized void commitChanges() throws IOException {
+    if (liveDocsDirty) {               // re-write deleted
+      si.advanceDelGen();
+
+      assert liveDocs.length() == si.docCount;
+
+      // We can write directly to the actual name (vs to a
+      // .tmp & renaming it) because the file is not live
+      // until segments file is written:
+      final String delFileName = si.getDelFileName();
+      boolean success = false;
+      try {
+        liveDocs.write(directory(), delFileName, IOContext.DEFAULT);
+        success = true;
+      } finally {
+        if (!success) {
+          try {
+            directory().deleteFile(delFileName);
+          } catch (Throwable t) {
+            // suppress this so we keep throwing the
+            // original exception
+          }
+        }
+      }
+      si.setDelCount(si.getDelCount()+pendingDeleteCount);
+      pendingDeleteCount = 0;
+      assert (maxDoc()-liveDocs.count()) == si.getDelCount(): "delete count mismatch during commit: info=" + si.getDelCount() + " vs BitVector=" + (maxDoc()-liveDocs.count());
+    } else {
+      assert pendingDeleteCount == 0;
+    }
+
+    liveDocsDirty = false;
+    hasChanges = false;
+  }
+
+  // TODO: remove deletions from SR
+  synchronized void deleteDocument(int docNum) throws IOException {
+    ensureOpen();
+    hasChanges = true;
+    doDelete(docNum);
+  }
+
+  // TODO: remove deletions from SR
+  void doDelete(int docNum) {
+    if (liveDocs == null) {
+      liveDocs = new BitVector(maxDoc());
+      liveDocs.setAll();
+      liveDocsRef = new AtomicInteger(1);
+    }
+    // there is more than 1 SegmentReader with a reference to this
+    // liveDocs BitVector so decRef the current liveDocsRef,
+    // clone the BitVector, create a new liveDocsRef
+    if (liveDocsRef.get() > 1) {
+      AtomicInteger oldRef = liveDocsRef;
+      liveDocs = cloneDeletedDocs(liveDocs);
+      liveDocsRef = new AtomicInteger(1);
+      oldRef.decrementAndGet();
+    }
+    liveDocsDirty = true;
+    if (liveDocs.getAndClear(docNum)) {
+      pendingDeleteCount++;
+    }
+  }
 }