You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ar...@apache.org on 2008/07/15 23:44:10 UTC
svn commit: r677059 [7/19] - in /incubator/lucene.net/trunk/C#/src: ./
Demo/DeleteFiles/ Demo/DemoLib/ Demo/IndexFiles/ Demo/IndexHtml/
Demo/SearchFiles/ Lucene.Net/ Lucene.Net/Analysis/ Lucene.Net/Index/
Lucene.Net/Search/ Lucene.Net/Search/Function/ ...
Added: incubator/lucene.net/trunk/C#/src/Test/Index/TestIndexReaderReopen.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Test/Index/TestIndexReaderReopen.cs?rev=677059&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Test/Index/TestIndexReaderReopen.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Test/Index/TestIndexReaderReopen.cs Tue Jul 15 14:44:04 2008
@@ -0,0 +1,1308 @@
+/*
+ * 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.
+ */
+
+using System;
+
+using NUnit.Framework;
+
+using Document = Lucene.Net.Documents.Document;
+using Field = Lucene.Net.Documents.Field;
+using Directory = Lucene.Net.Store.Directory;
+using RAMDirectory = Lucene.Net.Store.RAMDirectory;
+using WhitespaceAnalyzer = Lucene.Net.Analysis.WhitespaceAnalyzer;
+using StandardAnalyzer = Lucene.Net.Analysis.Standard.StandardAnalyzer;
+using Hits = Lucene.Net.Search.Hits;
+using IndexSearcher = Lucene.Net.Search.IndexSearcher;
+using TermQuery = Lucene.Net.Search.TermQuery;
+
+namespace Lucene.Net.Index
+{
+
+ [TestFixture]
+ public class TestIndexReaderReopen
+ {
+ private class AnonymousClassTestReopen : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen(Lucene.Net.Store.Directory dir1, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir1, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir1, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir1 = dir1;
+ this.enclosingInstance = enclosingInstance;
+ }
+
+ private Lucene.Net.Store.Directory dir1;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ TestIndexReaderReopen.ModifyIndex(i, dir1);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ return IndexReader.Open(dir1);
+ }
+ }
+
+ private class AnonymousClassTestReopen1 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen1(Lucene.Net.Store.Directory dir2, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir2, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir2, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir2 = dir2;
+ this.enclosingInstance = enclosingInstance;
+ }
+
+ private Lucene.Net.Store.Directory dir2;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ TestIndexReaderReopen.ModifyIndex(i, dir2);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ return IndexReader.Open(dir2);
+ }
+ }
+
+ private class AnonymousClassTestReopen2 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen2(Lucene.Net.Store.Directory dir1, Lucene.Net.Store.Directory dir2, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir1, dir2, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir1, Lucene.Net.Store.Directory dir2, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir1 = dir1;
+ this.dir2 = dir2;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private Lucene.Net.Store.Directory dir1;
+ private Lucene.Net.Store.Directory dir2;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ TestIndexReaderReopen.ModifyIndex(i, dir1);
+ TestIndexReaderReopen.ModifyIndex(i, dir2);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ ParallelReader pr = new ParallelReader();
+ pr.Add(IndexReader.Open(dir1));
+ pr.Add(IndexReader.Open(dir2));
+ return pr;
+ }
+ }
+
+ private class AnonymousClassTestReopen3 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen3(Lucene.Net.Store.Directory dir3, Lucene.Net.Store.Directory dir4, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir3, dir4, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir3, Lucene.Net.Store.Directory dir4, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir3 = dir3;
+ this.dir4 = dir4;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private Lucene.Net.Store.Directory dir3;
+ private Lucene.Net.Store.Directory dir4;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ TestIndexReaderReopen.ModifyIndex(i, dir3);
+ TestIndexReaderReopen.ModifyIndex(i, dir4);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ ParallelReader pr = new ParallelReader();
+ pr.Add(IndexReader.Open(dir3));
+ pr.Add(IndexReader.Open(dir4));
+ pr.Add(new FilterIndexReader(IndexReader.Open(dir3)));
+ return pr;
+ }
+ }
+
+ private class AnonymousClassTestReopen4 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen4(Lucene.Net.Store.Directory dir1, Lucene.Net.Store.Directory dir2, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir1, dir2, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir1, Lucene.Net.Store.Directory dir2, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir1 = dir1;
+ this.dir2 = dir2;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private Lucene.Net.Store.Directory dir1;
+ private Lucene.Net.Store.Directory dir2;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ TestIndexReaderReopen.ModifyIndex(i, dir1);
+ TestIndexReaderReopen.ModifyIndex(i, dir2);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ return new MultiReader(new IndexReader[]{IndexReader.Open(dir1), IndexReader.Open(dir2)});
+ }
+ }
+
+ private class AnonymousClassTestReopen5 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen5(Lucene.Net.Store.Directory dir3, Lucene.Net.Store.Directory dir4, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir3, dir4, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir3, Lucene.Net.Store.Directory dir4, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir3 = dir3;
+ this.dir4 = dir4;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private Lucene.Net.Store.Directory dir3;
+ private Lucene.Net.Store.Directory dir4;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ TestIndexReaderReopen.ModifyIndex(i, dir3);
+ TestIndexReaderReopen.ModifyIndex(i, dir4);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ return new MultiReader(new IndexReader[]{IndexReader.Open(dir3), IndexReader.Open(dir4), new FilterIndexReader(IndexReader.Open(dir3))});
+ }
+ }
+
+ private class AnonymousClassTestReopen6 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen6(Lucene.Net.Store.Directory dir1, Lucene.Net.Store.Directory dir4, Lucene.Net.Store.Directory dir5, Lucene.Net.Store.Directory dir2, Lucene.Net.Store.Directory dir3, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir1, dir4, dir5, dir2, dir3, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir1, Lucene.Net.Store.Directory dir4, Lucene.Net.Store.Directory dir5, Lucene.Net.Store.Directory dir2, Lucene.Net.Store.Directory dir3, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir1 = dir1;
+ this.dir4 = dir4;
+ this.dir5 = dir5;
+ this.dir2 = dir2;
+ this.dir3 = dir3;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private Lucene.Net.Store.Directory dir1;
+ private Lucene.Net.Store.Directory dir4;
+ private Lucene.Net.Store.Directory dir5;
+ private Lucene.Net.Store.Directory dir2;
+ private Lucene.Net.Store.Directory dir3;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ protected internal override void ModifyIndex(int i)
+ {
+ // only change norms in this index to maintain the same number of docs for each of ParallelReader's subreaders
+ if (i == 1)
+ TestIndexReaderReopen.ModifyIndex(i, dir1);
+
+ TestIndexReaderReopen.ModifyIndex(i, dir4);
+ TestIndexReaderReopen.ModifyIndex(i, dir5);
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ ParallelReader pr = new ParallelReader();
+ pr.Add(IndexReader.Open(dir1));
+ pr.Add(IndexReader.Open(dir2));
+ MultiReader mr = new MultiReader(new IndexReader[]{IndexReader.Open(dir3), IndexReader.Open(dir4)});
+ return new MultiReader(new IndexReader[]{pr, mr, IndexReader.Open(dir5)});
+ }
+ }
+
+ private class AnonymousClassTestReopen7 : TestReopen_Renamed_Class
+ {
+ public AnonymousClassTestReopen7(Lucene.Net.Store.Directory dir, int n, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(dir, n, enclosingInstance);
+ }
+ private void InitBlock(Lucene.Net.Store.Directory dir, int n, TestIndexReaderReopen enclosingInstance)
+ {
+ this.dir = dir;
+ this.n = n;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private Lucene.Net.Store.Directory dir;
+ private int n;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+ protected internal override void ModifyIndex(int i)
+ {
+ if (i % 3 == 0)
+ {
+ IndexReader modifier = IndexReader.Open(dir);
+ modifier.SetNorm(i, "field1", 50);
+ modifier.Close();
+ }
+ else if (i % 3 == 1)
+ {
+ IndexReader modifier = IndexReader.Open(dir);
+ modifier.DeleteDocument(i);
+ modifier.Close();
+ }
+ else
+ {
+ IndexWriter modifier = new IndexWriter(dir, new StandardAnalyzer());
+ modifier.AddDocument(Lucene.Net.Index.TestIndexReaderReopen.CreateDocument(n + i, 6));
+ modifier.Close();
+ }
+ }
+
+ protected internal override IndexReader OpenReader()
+ {
+ return IndexReader.Open(dir);
+ }
+ }
+
+ private class AnonymousClassReaderThreadTask : ReaderThreadTask
+ {
+ public AnonymousClassReaderThreadTask(int index, Lucene.Net.Index.IndexReader r, TestReopen_Renamed_Class test, System.Collections.Hashtable readersToClose, System.Collections.IList readers, System.Random rnd, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(index, r, test, readersToClose, readers, rnd, enclosingInstance);
+ }
+ private void InitBlock(int index, Lucene.Net.Index.IndexReader r, TestReopen_Renamed_Class test, System.Collections.Hashtable readersToClose, System.Collections.IList readers, System.Random rnd, TestIndexReaderReopen enclosingInstance)
+ {
+ this.index = index;
+ this.r = r;
+ this.test = test;
+ this.readersToClose = readersToClose;
+ this.readers = readers;
+ this.rnd = rnd;
+ this.enclosingInstance = enclosingInstance;
+ }
+
+ private int index;
+ private Lucene.Net.Index.IndexReader r;
+ private TestReopen_Renamed_Class test;
+ private System.Collections.Hashtable readersToClose;
+ private System.Collections.IList readers;
+ private System.Random rnd;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+
+ public override void Run()
+ {
+ while (!stopped)
+ {
+ if (index % 2 == 0)
+ {
+ // refresh reader synchronized
+ ReaderCouple c = (Enclosing_Instance.RefreshReader(r, test, index, true));
+ if (!readersToClose.Contains(c.newReader))
+ readersToClose.Add(c.newReader, c.newReader);
+ if (!readersToClose.Contains(c.refreshedReader))
+ readersToClose.Add(c.refreshedReader, c.refreshedReader);
+ readers.Add(c);
+ // prevent too many readers
+ break;
+ }
+ else
+ {
+ // not synchronized
+ IndexReader refreshed = r.Reopen();
+
+
+ IndexSearcher searcher = new IndexSearcher(refreshed);
+ Hits hits = searcher.Search(new TermQuery(new Term("field1", "a" + rnd.Next(refreshed.MaxDoc()))));
+ if (hits.Length() > 0)
+ {
+ hits.Doc(0);
+ }
+
+ // r might have changed because this is not a
+ // synchronized method. However we don't want
+ // to make it synchronized to test
+ // thread-safety of IndexReader.close().
+ // That's why we add refreshed also to
+ // readersToClose, because double closing is fine
+ if (refreshed != r)
+ {
+ refreshed.Close();
+ }
+ if (!readersToClose.Contains(refreshed))
+ readersToClose.Add(refreshed, refreshed);
+ }
+ try
+ {
+ lock (this)
+ {
+ System.Threading.Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+ }
+ }
+ catch (System.Threading.ThreadInterruptedException)
+ {
+ }
+ }
+ }
+ }
+
+ private class AnonymousClassReaderThreadTask1 : ReaderThreadTask
+ {
+ public AnonymousClassReaderThreadTask1(System.Collections.IList readers, System.Random rnd, TestIndexReaderReopen enclosingInstance)
+ {
+ InitBlock(readers, rnd, enclosingInstance);
+ }
+ private void InitBlock(System.Collections.IList readers, System.Random rnd, TestIndexReaderReopen enclosingInstance)
+ {
+ this.readers = readers;
+ this.rnd = rnd;
+ this.enclosingInstance = enclosingInstance;
+ }
+ private System.Collections.IList readers;
+ private System.Random rnd;
+ private TestIndexReaderReopen enclosingInstance;
+ public TestIndexReaderReopen Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+ public override void Run()
+ {
+ while (!stopped)
+ {
+ int numReaders = readers.Count;
+ if (numReaders > 0)
+ {
+ ReaderCouple c = (ReaderCouple) readers[rnd.Next(numReaders)];
+ TestIndexReader.AssertIndexEquals(c.newReader, c.refreshedReader);
+ }
+
+ try
+ {
+ lock (this)
+ {
+ System.Threading.Monitor.Wait(this, TimeSpan.FromMilliseconds(100));
+ }
+ }
+ catch (System.Threading.ThreadInterruptedException)
+ {
+ }
+ }
+ }
+ }
+
+ [Test]
+ public virtual void TestReopen()
+ {
+ Directory dir1 = new RAMDirectory();
+
+ CreateIndex(dir1, false);
+ PerformDefaultTests(new AnonymousClassTestReopen(dir1, this));
+
+ Directory dir2 = new RAMDirectory();
+
+ CreateIndex(dir2, true);
+ PerformDefaultTests(new AnonymousClassTestReopen1(dir2, this));
+ }
+
+ [Test]
+ public virtual void TestParallelReaderReopen()
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, true);
+ Directory dir2 = new RAMDirectory();
+ CreateIndex(dir2, true);
+
+ PerformDefaultTests(new AnonymousClassTestReopen2(dir1, dir2, this));
+
+ Directory dir3 = new RAMDirectory();
+ CreateIndex(dir3, true);
+ Directory dir4 = new RAMDirectory();
+ CreateIndex(dir4, true);
+
+ PerformTestsWithExceptionInReopen(new AnonymousClassTestReopen3(dir3, dir4, this));
+ }
+
+ [Test]
+ public virtual void TestMultiReaderReopen()
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, true);
+ Directory dir2 = new RAMDirectory();
+ CreateIndex(dir2, true);
+
+ PerformDefaultTests(new AnonymousClassTestReopen4(dir1, dir2, this));
+
+ Directory dir3 = new RAMDirectory();
+ CreateIndex(dir3, true);
+ Directory dir4 = new RAMDirectory();
+ CreateIndex(dir4, true);
+
+ PerformTestsWithExceptionInReopen(new AnonymousClassTestReopen5(dir3, dir4, this));
+ }
+
+ [Test]
+ public virtual void TestMixedReaders()
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, true);
+ Directory dir2 = new RAMDirectory();
+ CreateIndex(dir2, true);
+ Directory dir3 = new RAMDirectory();
+ CreateIndex(dir3, false);
+ Directory dir4 = new RAMDirectory();
+ CreateIndex(dir4, true);
+ Directory dir5 = new RAMDirectory();
+ CreateIndex(dir5, false);
+
+ PerformDefaultTests(new AnonymousClassTestReopen6(dir1, dir4, dir5, dir2, dir3, this));
+ }
+
+
+ private void PerformDefaultTests(TestReopen_Renamed_Class test)
+ {
+ IndexReader index1 = test.OpenReader();
+ IndexReader index2 = test.OpenReader();
+
+ TestIndexReader.AssertIndexEquals(index1, index2);
+
+ // verify that reopen() does not return a new reader instance
+ // in case the index has no changes
+ ReaderCouple couple = RefreshReader(index2, false);
+ Assert.IsTrue(couple.refreshedReader == index2);
+
+ couple = RefreshReader(index2, test, 0, true);
+ index1 = couple.newReader;
+ IndexReader index2_refreshed = couple.refreshedReader;
+ index2.Close();
+
+ // test if refreshed reader and newly opened reader return equal results
+ TestIndexReader.AssertIndexEquals(index1, index2_refreshed);
+
+ index1.Close();
+ index2_refreshed.Close();
+ AssertReaderClosed(index2, true, true);
+ AssertReaderClosed(index2_refreshed, true, true);
+
+ index2 = test.OpenReader();
+
+ for (int i = 1; i < 4; i++)
+ {
+
+ index1.Close();
+ couple = RefreshReader(index2, test, i, true);
+ // refresh IndexReader
+ index2.Close();
+
+ index2 = couple.refreshedReader;
+ index1 = couple.newReader;
+ TestIndexReader.AssertIndexEquals(index1, index2);
+ }
+
+ index1.Close();
+ index2.Close();
+ AssertReaderClosed(index1, true, true);
+ AssertReaderClosed(index2, true, true);
+ }
+
+ [Test]
+ public virtual void TestReferenceCounting()
+ {
+
+ for (int mode = 0; mode < 4; mode++)
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, true);
+
+ IndexReader reader0 = IndexReader.Open(dir1);
+ AssertRefCountEquals(1, reader0);
+
+ Assert.IsTrue(reader0 is MultiSegmentReader);
+ SegmentReader[] subReaders0 = ((MultiSegmentReader) reader0).GetSubReaders();
+ for (int i = 0; i < subReaders0.Length; i++)
+ {
+ AssertRefCountEquals(1, subReaders0[i]);
+ }
+
+ // delete first document, so that only one of the subReaders have to be re-opened
+ IndexReader modifier = IndexReader.Open(dir1);
+ modifier.DeleteDocument(0);
+ modifier.Close();
+
+ IndexReader reader1 = RefreshReader(reader0, true).refreshedReader;
+ Assert.IsTrue(reader1 is MultiSegmentReader);
+ SegmentReader[] subReaders1 = ((MultiSegmentReader) reader1).GetSubReaders();
+ Assert.AreEqual(subReaders0.Length, subReaders1.Length);
+
+ for (int i = 0; i < subReaders0.Length; i++)
+ {
+ AssertRefCountEquals(2, subReaders0[i]);
+ if (subReaders0[i] != subReaders1[i])
+ {
+ AssertRefCountEquals(1, subReaders1[i]);
+ }
+ }
+
+ // delete first document, so that only one of the subReaders have to be re-opened
+ modifier = IndexReader.Open(dir1);
+ modifier.DeleteDocument(1);
+ modifier.Close();
+
+ IndexReader reader2 = RefreshReader(reader1, true).refreshedReader;
+ Assert.IsTrue(reader2 is MultiSegmentReader);
+ SegmentReader[] subReaders2 = ((MultiSegmentReader) reader2).GetSubReaders();
+ Assert.AreEqual(subReaders1.Length, subReaders2.Length);
+
+ for (int i = 0; i < subReaders2.Length; i++)
+ {
+ if (subReaders2[i] == subReaders1[i])
+ {
+ if (subReaders1[i] == subReaders0[i])
+ {
+ AssertRefCountEquals(3, subReaders2[i]);
+ }
+ else
+ {
+ AssertRefCountEquals(2, subReaders2[i]);
+ }
+ }
+ else
+ {
+ AssertRefCountEquals(1, subReaders2[i]);
+ if (subReaders0[i] == subReaders1[i])
+ {
+ AssertRefCountEquals(3, subReaders2[i]);
+ AssertRefCountEquals(2, subReaders0[i]);
+ }
+ else
+ {
+ AssertRefCountEquals(3, subReaders0[i]);
+ AssertRefCountEquals(1, subReaders1[i]);
+ }
+ }
+ }
+
+ IndexReader reader3 = RefreshReader(reader0, true).refreshedReader;
+ Assert.IsTrue(reader3 is MultiSegmentReader);
+ SegmentReader[] subReaders3 = ((MultiSegmentReader) reader3).GetSubReaders();
+ Assert.AreEqual(subReaders3.Length, subReaders0.Length);
+
+ // try some permutations
+ switch (mode)
+ {
+
+ case 0:
+ reader0.Close();
+ reader1.Close();
+ reader2.Close();
+ reader3.Close();
+ break;
+
+ case 1:
+ reader3.Close();
+ reader2.Close();
+ reader1.Close();
+ reader0.Close();
+ break;
+
+ case 2:
+ reader2.Close();
+ reader3.Close();
+ reader0.Close();
+ reader1.Close();
+ break;
+
+ case 3:
+ reader1.Close();
+ reader3.Close();
+ reader2.Close();
+ reader0.Close();
+ break;
+ }
+
+ AssertReaderClosed(reader0, true, true);
+ AssertReaderClosed(reader1, true, true);
+ AssertReaderClosed(reader2, true, true);
+ AssertReaderClosed(reader3, true, true);
+ }
+ }
+
+
+ [Test]
+ public virtual void TestReferenceCountingMultiReader()
+ {
+ for (int mode = 0; mode <= 1; mode++)
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, false);
+ Directory dir2 = new RAMDirectory();
+ CreateIndex(dir2, true);
+
+ IndexReader reader1 = IndexReader.Open(dir1);
+ AssertRefCountEquals(1, reader1);
+
+ IndexReader multiReader1 = new MultiReader(new IndexReader[]{reader1, IndexReader.Open(dir2)}, (mode == 0));
+ ModifyIndex(0, dir2);
+ AssertRefCountEquals(1 + mode, reader1);
+
+ IndexReader multiReader2 = multiReader1.Reopen();
+ // index1 hasn't changed, so multiReader2 should share reader1 now with multiReader1
+ AssertRefCountEquals(2 + mode, reader1);
+
+ ModifyIndex(0, dir1);
+ IndexReader reader2 = reader1.Reopen();
+ AssertRefCountEquals(3 + mode, reader1);
+
+ ModifyIndex(1, dir1);
+ IndexReader reader3 = reader2.Reopen();
+ AssertRefCountEquals(4 + mode, reader1);
+ AssertRefCountEquals(1, reader2);
+
+ multiReader1.Close();
+ AssertRefCountEquals(3 + mode, reader1);
+
+ multiReader1.Close();
+ AssertRefCountEquals(3 + mode, reader1);
+
+ reader1.Close();
+ AssertRefCountEquals(3, reader1);
+
+ multiReader2.Close();
+ AssertRefCountEquals(2, reader1);
+
+ multiReader2.Close();
+ AssertRefCountEquals(2, reader1);
+
+ reader3.Close();
+ AssertRefCountEquals(1, reader1);
+ AssertReaderOpen(reader1);
+
+ reader2.Close();
+ AssertRefCountEquals(0, reader1);
+ AssertReaderClosed(reader1, true, false);
+
+ reader2.Close();
+ AssertRefCountEquals(0, reader1);
+
+ reader3.Close();
+ AssertRefCountEquals(0, reader1);
+ AssertReaderClosed(reader1, true, true);
+ }
+ }
+
+ [Test]
+ public virtual void TestReferenceCountingParallelReader()
+ {
+ for (int mode = 0; mode <= 1; mode++)
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, false);
+ Directory dir2 = new RAMDirectory();
+ CreateIndex(dir2, true);
+
+ IndexReader reader1 = IndexReader.Open(dir1);
+ AssertRefCountEquals(1, reader1);
+
+ ParallelReader parallelReader1 = new ParallelReader(mode == 0);
+ parallelReader1.Add(reader1);
+ parallelReader1.Add(IndexReader.Open(dir2));
+ ModifyIndex(1, dir2);
+ AssertRefCountEquals(1 + mode, reader1);
+
+ IndexReader parallelReader2 = parallelReader1.Reopen();
+ // index1 hasn't changed, so parallelReader2 should share reader1 now with multiReader1
+ AssertRefCountEquals(2 + mode, reader1);
+
+ ModifyIndex(0, dir1);
+ ModifyIndex(0, dir2);
+ IndexReader reader2 = reader1.Reopen();
+ AssertRefCountEquals(3 + mode, reader1);
+
+ ModifyIndex(4, dir1);
+ IndexReader reader3 = reader2.Reopen();
+ AssertRefCountEquals(4 + mode, reader1);
+ AssertRefCountEquals(1, reader2);
+
+ parallelReader1.Close();
+ AssertRefCountEquals(3 + mode, reader1);
+
+ parallelReader1.Close();
+ AssertRefCountEquals(3 + mode, reader1);
+
+ reader1.Close();
+ AssertRefCountEquals(3, reader1);
+
+ parallelReader2.Close();
+ AssertRefCountEquals(2, reader1);
+
+ parallelReader2.Close();
+ AssertRefCountEquals(2, reader1);
+
+ reader3.Close();
+ AssertRefCountEquals(1, reader1);
+ AssertReaderOpen(reader1);
+
+ reader2.Close();
+ AssertRefCountEquals(0, reader1);
+ AssertReaderClosed(reader1, true, false);
+
+ reader2.Close();
+ AssertRefCountEquals(0, reader1);
+
+ reader3.Close();
+ AssertRefCountEquals(0, reader1);
+ AssertReaderClosed(reader1, true, true);
+ }
+ }
+
+ [Test]
+ public virtual void TestNormsRefCounting()
+ {
+ Directory dir1 = new RAMDirectory();
+ CreateIndex(dir1, false);
+
+ SegmentReader reader1 = (SegmentReader) IndexReader.Open(dir1);
+ IndexReader modifier = IndexReader.Open(dir1);
+ modifier.DeleteDocument(0);
+ modifier.Close();
+
+ SegmentReader reader2 = (SegmentReader) reader1.Reopen();
+ modifier = IndexReader.Open(dir1);
+ modifier.SetNorm(1, "field1", 50);
+ modifier.SetNorm(1, "field2", 50);
+ modifier.Close();
+
+ SegmentReader reader3 = (SegmentReader) reader2.Reopen();
+ modifier = IndexReader.Open(dir1);
+ modifier.DeleteDocument(2);
+ modifier.Close();
+ SegmentReader reader4 = (SegmentReader) reader3.Reopen();
+
+ modifier = IndexReader.Open(dir1);
+ modifier.DeleteDocument(3);
+ modifier.Close();
+ SegmentReader reader5 = (SegmentReader) reader3.Reopen();
+
+ // Now reader2-reader5 references reader1. reader1 and reader2
+ // share the same norms. reader3, reader4, reader5 also share norms.
+ AssertRefCountEquals(5, reader1);
+ Assert.IsFalse(reader1.NormsClosed());
+ reader1.Close();
+ AssertRefCountEquals(4, reader1);
+ Assert.IsFalse(reader1.NormsClosed());
+ reader2.Close();
+ AssertRefCountEquals(3, reader1);
+ // now the norms for field1 and field2 should be closed
+ Assert.IsTrue(reader1.NormsClosed("field1"));
+ Assert.IsTrue(reader1.NormsClosed("field2"));
+ // but the norms for field3 and field4 should still be open
+ Assert.IsFalse(reader1.NormsClosed("field3"));
+ Assert.IsFalse(reader1.NormsClosed("field4"));
+
+ reader3.Close();
+ AssertRefCountEquals(2, reader1);
+ Assert.IsFalse(reader3.NormsClosed());
+ reader5.Close();
+ AssertRefCountEquals(1, reader1);
+ Assert.IsFalse(reader3.NormsClosed());
+ reader4.Close();
+ AssertRefCountEquals(0, reader1);
+
+ // and now all norms that reader1 used should be closed
+ Assert.IsTrue(reader1.NormsClosed());
+
+ // now that reader3, reader4 and reader5 are closed,
+ // the norms that those three readers shared should be
+ // closed as well
+ Assert.IsTrue(reader3.NormsClosed());
+ }
+
+ private void PerformTestsWithExceptionInReopen(TestReopen_Renamed_Class test)
+ {
+ IndexReader index1 = test.OpenReader();
+ IndexReader index2 = test.OpenReader();
+
+ TestIndexReader.AssertIndexEquals(index1, index2);
+
+ try
+ {
+ ReaderCouple couple = RefreshReader(index1, test, 0, true);
+ Assert.Fail("Expected exception not thrown.");
+ }
+ catch (System.Exception)
+ {
+ // expected exception
+ }
+
+ // index2 should still be usable and unaffected by the failed reopen() call
+ TestIndexReader.AssertIndexEquals(index1, index2);
+ }
+
+ [Test]
+ public virtual void TestThreadSafety()
+ {
+ Directory dir = new RAMDirectory();
+ int n = 150;
+
+ IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer());
+ for (int i = 0; i < n; i++)
+ {
+ writer.AddDocument(CreateDocument(i, 3));
+ }
+ writer.Optimize();
+ writer.Close();
+
+ TestReopen_Renamed_Class test = new AnonymousClassTestReopen7(dir, n, this);
+
+ System.Collections.IList readers = (System.Collections.IList) System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(new System.Collections.ArrayList()));
+ IndexReader firstReader = IndexReader.Open(dir);
+ IndexReader reader = firstReader;
+ System.Random rnd = new System.Random();
+
+ ReaderThread[] threads = new ReaderThread[n];
+ System.Collections.Hashtable readersToClose = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
+
+ for (int i = 0; i < n; i++)
+ {
+ if (i % 10 == 0)
+ {
+ IndexReader refreshed = reader.Reopen();
+ if (refreshed != reader)
+ {
+ if (!readersToClose.Contains(reader))
+ readersToClose.Add(reader, reader);
+ }
+ reader = refreshed;
+ }
+ IndexReader r = reader;
+
+ int index = i;
+
+ ReaderThreadTask task;
+
+ if (i < 20 || (i >= 50 && i < 70) || i > 90)
+ {
+ task = new AnonymousClassReaderThreadTask(index, r, test, readersToClose, readers, rnd, this);
+ }
+ else
+ {
+ task = new AnonymousClassReaderThreadTask1(readers, rnd, this);
+ }
+
+ threads[i] = new ReaderThread(task);
+ threads[i].Start();
+ }
+
+ lock (this)
+ {
+ try
+ {
+ System.Threading.Monitor.Wait(this, 15000);
+ }
+ catch (System.Threading.ThreadInterruptedException)
+ {
+ }
+ }
+
+ for (int i = 0; i < n; i++)
+ {
+ if (threads[i] != null)
+ {
+ threads[i].StopThread();
+ }
+ }
+
+ for (int i = 0; i < n; i++)
+ {
+ if (threads[i] != null)
+ {
+ try
+ {
+ threads[i].Join();
+ if (threads[i].exception != null)
+ {
+ throw threads[i].exception;
+ }
+ }
+ catch (System.Threading.ThreadInterruptedException)
+ {
+ }
+ }
+ }
+
+ System.Collections.IEnumerator it = readersToClose.Keys.GetEnumerator();
+ while (it.MoveNext())
+ {
+ ((IndexReader) it.Current).Close();
+ }
+
+ firstReader.Close();
+ reader.Close();
+
+ it = readersToClose.Keys.GetEnumerator();
+ while (it.MoveNext())
+ {
+ AssertReaderClosed((IndexReader) it.Current, true, true);
+ }
+
+ AssertReaderClosed(reader, true, true);
+ AssertReaderClosed(firstReader, true, true);
+ }
+
+ private class ReaderCouple
+ {
+ internal ReaderCouple(IndexReader r1, IndexReader r2)
+ {
+ newReader = r1;
+ refreshedReader = r2;
+ }
+
+ internal IndexReader newReader;
+ internal IndexReader refreshedReader;
+ }
+
+ abstract internal class ReaderThreadTask
+ {
+ protected internal bool stopped;
+ public virtual void Stop()
+ {
+ this.stopped = true;
+ }
+
+ public abstract void Run();
+ }
+
+ private class ReaderThread : SupportClass.ThreadClass
+ {
+ private ReaderThreadTask task;
+ internal System.Exception exception;
+
+
+ internal ReaderThread(ReaderThreadTask task)
+ {
+ this.task = task;
+ }
+
+ public virtual void StopThread()
+ {
+ this.task.Stop();
+ }
+
+ override public void Run()
+ {
+ try
+ {
+ this.task.Run();
+ }
+ catch (System.Exception e)
+ {
+ this.exception = e;
+ }
+ }
+ }
+
+ private System.Object createReaderMutex = new System.Object();
+
+ private ReaderCouple RefreshReader(IndexReader reader, bool hasChanges)
+ {
+ return RefreshReader(reader, null, - 1, hasChanges);
+ }
+
+ private ReaderCouple RefreshReader(IndexReader reader, TestReopen_Renamed_Class test, int modify, bool hasChanges)
+ {
+ lock (createReaderMutex)
+ {
+ IndexReader r = null;
+ if (test != null)
+ {
+ test.ModifyIndex(modify);
+ r = test.OpenReader();
+ }
+
+ IndexReader refreshed = reader.Reopen();
+ if (hasChanges)
+ {
+ if (refreshed == reader)
+ {
+ Assert.Fail("No new IndexReader instance created during refresh.");
+ }
+ }
+ else
+ {
+ if (refreshed != reader)
+ {
+ Assert.Fail("New IndexReader instance created during refresh even though index had no changes.");
+ }
+ }
+
+ return new ReaderCouple(r, refreshed);
+ }
+ }
+
+ private static void CreateIndex(Directory dir, bool multiSegment)
+ {
+ IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer());
+
+ w.SetMergePolicy(new LogDocMergePolicy());
+
+ for (int i = 0; i < 100; i++)
+ {
+ w.AddDocument(CreateDocument(i, 4));
+ if (multiSegment && (i % 10) == 0)
+ {
+ w.Flush();
+ }
+ }
+
+ if (!multiSegment)
+ {
+ w.Optimize();
+ }
+
+ w.Close();
+
+ IndexReader r = IndexReader.Open(dir);
+ if (multiSegment)
+ {
+ Assert.IsTrue(r is MultiSegmentReader);
+ }
+ else
+ {
+ Assert.IsTrue(r is SegmentReader);
+ }
+ r.Close();
+ }
+
+ private static Document CreateDocument(int n, int numFields)
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ Document doc = new Document();
+ sb.Append("a");
+ sb.Append(n);
+ doc.Add(new Field("field1", sb.ToString(), Field.Store.YES, Field.Index.TOKENIZED));
+ sb.Append(" b");
+ sb.Append(n);
+ for (int i = 1; i < numFields; i++)
+ {
+ doc.Add(new Field("field" + (i + 1), sb.ToString(), Field.Store.YES, Field.Index.TOKENIZED));
+ }
+ return doc;
+ }
+
+ private static void ModifyIndex(int i, Directory dir)
+ {
+ switch (i)
+ {
+
+ case 0: {
+ IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer());
+ w.DeleteDocuments(new Term("field2", "a11"));
+ w.DeleteDocuments(new Term("field2", "b30"));
+ w.Close();
+ break;
+ }
+
+ case 1: {
+ IndexReader reader = IndexReader.Open(dir);
+ reader.SetNorm(4, "field1", 123);
+ reader.SetNorm(44, "field2", 222);
+ reader.SetNorm(44, "field4", 22);
+ reader.Close();
+ break;
+ }
+
+ case 2: {
+ IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer());
+ w.Optimize();
+ w.Close();
+ break;
+ }
+
+ case 3: {
+ IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer());
+ w.AddDocument(CreateDocument(101, 4));
+ w.Optimize();
+ w.AddDocument(CreateDocument(102, 4));
+ w.AddDocument(CreateDocument(103, 4));
+ w.Close();
+ break;
+ }
+
+ case 4: {
+ IndexReader reader = IndexReader.Open(dir);
+ reader.SetNorm(5, "field1", 123);
+ reader.SetNorm(55, "field2", 222);
+ reader.Close();
+ break;
+ }
+ }
+ }
+
+ private void AssertReaderClosed(IndexReader reader, bool checkSubReaders, bool checkNormsClosed)
+ {
+ Assert.AreEqual(0, reader.GetRefCount());
+
+ if (checkNormsClosed && reader is SegmentReader)
+ {
+ Assert.IsTrue(((SegmentReader) reader).NormsClosed());
+ }
+
+ if (checkSubReaders)
+ {
+ if (reader is MultiSegmentReader)
+ {
+ SegmentReader[] subReaders = ((MultiSegmentReader) reader).GetSubReaders();
+ for (int i = 0; i < subReaders.Length; i++)
+ {
+ AssertReaderClosed(subReaders[i], checkSubReaders, checkNormsClosed);
+ }
+ }
+
+ if (reader is MultiReader)
+ {
+ IndexReader[] subReaders = ((MultiReader) reader).GetSubReaders();
+ for (int i = 0; i < subReaders.Length; i++)
+ {
+ AssertReaderClosed(subReaders[i], checkSubReaders, checkNormsClosed);
+ }
+ }
+
+ if (reader is ParallelReader)
+ {
+ IndexReader[] subReaders = ((ParallelReader) reader).GetSubReaders();
+ for (int i = 0; i < subReaders.Length; i++)
+ {
+ AssertReaderClosed(subReaders[i], checkSubReaders, checkNormsClosed);
+ }
+ }
+ }
+ }
+
+ private void AssertReaderOpen(IndexReader reader)
+ {
+ reader.EnsureOpen();
+
+ if (reader is MultiSegmentReader)
+ {
+ SegmentReader[] subReaders = ((MultiSegmentReader) reader).GetSubReaders();
+ for (int i = 0; i < subReaders.Length; i++)
+ {
+ AssertReaderOpen(subReaders[i]);
+ }
+ }
+ }
+
+ private void AssertRefCountEquals(int refCount, IndexReader reader)
+ {
+ Assert.AreEqual(refCount, reader.GetRefCount(), "Reader has wrong refCount value.");
+ }
+
+
+ private abstract class TestReopen_Renamed_Class
+ {
+ protected internal abstract IndexReader OpenReader();
+ protected internal abstract void ModifyIndex(int i);
+ }
+ }
+}
\ No newline at end of file