http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestSegmentTermEnum.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Index/TestSegmentTermEnum.cs b/src/Lucene.Net.Tests/Index/TestSegmentTermEnum.cs new file mode 100644 index 0000000..3ed504b --- /dev/null +++ b/src/Lucene.Net.Tests/Index/TestSegmentTermEnum.cs @@ -0,0 +1,152 @@ +using Lucene.Net.Documents; + +namespace Lucene.Net.Index +{ + using NUnit.Framework; + using BytesRef = Lucene.Net.Util.BytesRef; + using Directory = Lucene.Net.Store.Directory; + using Document = Documents.Document; + + /* + * 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 Field = Field; + using Lucene41PostingsFormat = Lucene.Net.Codecs.Lucene41.Lucene41PostingsFormat; + using LuceneTestCase = Lucene.Net.Util.LuceneTestCase; + using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer; + using TestUtil = Lucene.Net.Util.TestUtil; + + [TestFixture] + public class TestSegmentTermEnum : LuceneTestCase + { + internal Directory Dir; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + Dir = NewDirectory(); + } + + [TearDown] + public override void TearDown() + { + Dir.Dispose(); + base.TearDown(); + } + + [Test] + public virtual void TestTermEnum() + { + IndexWriter writer = null; + + writer = new IndexWriter(Dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()))); + + // ADD 100 documents with term : aaa + // add 100 documents with terms: aaa bbb + // Therefore, term 'aaa' has document frequency of 200 and term 'bbb' 100 + for (int i = 0; i < 100; i++) + { + AddDoc(writer, "aaa"); + AddDoc(writer, "aaa bbb"); + } + + writer.Dispose(); + + // verify document frequency of terms in an multi segment index + VerifyDocFreq(); + + // merge segments + writer = new IndexWriter(Dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetOpenMode(OpenMode.APPEND)); + writer.ForceMerge(1); + writer.Dispose(); + + // verify document frequency of terms in a single segment index + VerifyDocFreq(); + } + + [Test] + public virtual void TestPrevTermAtEnd() + { + IndexWriter writer = new IndexWriter(Dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetCodec(TestUtil.AlwaysPostingsFormat(new Lucene41PostingsFormat()))); + AddDoc(writer, "aaa bbb"); + writer.Dispose(); + SegmentReader reader = GetOnlySegmentReader(DirectoryReader.Open(Dir)); + TermsEnum terms = reader.Fields.GetTerms("content").GetIterator(null); + Assert.IsNotNull(terms.Next()); + Assert.AreEqual("aaa", terms.Term.Utf8ToString()); + Assert.IsNotNull(terms.Next()); + long ordB; + try + { + ordB = terms.Ord; + } +#pragma warning disable 168 + catch (System.NotSupportedException uoe) +#pragma warning restore 168 + { + // ok -- codec is not required to support ord + reader.Dispose(); + return; + } + Assert.AreEqual("bbb", terms.Term.Utf8ToString()); + Assert.IsNull(terms.Next()); + + terms.SeekExact(ordB); + Assert.AreEqual("bbb", terms.Term.Utf8ToString()); + reader.Dispose(); + } + + private void VerifyDocFreq() + { + IndexReader reader = DirectoryReader.Open(Dir); + TermsEnum termEnum = MultiFields.GetTerms(reader, "content").GetIterator(null); + + // create enumeration of all terms + // go to the first term (aaa) + termEnum.Next(); + // assert that term is 'aaa' + Assert.AreEqual("aaa", termEnum.Term.Utf8ToString()); + Assert.AreEqual(200, termEnum.DocFreq); + // go to the second term (bbb) + termEnum.Next(); + // assert that term is 'bbb' + Assert.AreEqual("bbb", termEnum.Term.Utf8ToString()); + Assert.AreEqual(100, termEnum.DocFreq); + + // create enumeration of terms after term 'aaa', + // including 'aaa' + termEnum.SeekCeil(new BytesRef("aaa")); + // assert that term is 'aaa' + Assert.AreEqual("aaa", termEnum.Term.Utf8ToString()); + Assert.AreEqual(200, termEnum.DocFreq); + // go to term 'bbb' + termEnum.Next(); + // assert that term is 'bbb' + Assert.AreEqual("bbb", termEnum.Term.Utf8ToString()); + Assert.AreEqual(100, termEnum.DocFreq); + reader.Dispose(); + } + + private void AddDoc(IndexWriter writer, string value) + { + Document doc = new Document(); + doc.Add(NewTextField("content", value, Field.Store.NO)); + writer.AddDocument(doc); + } + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestSizeBoundedForceMerge.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Index/TestSizeBoundedForceMerge.cs b/src/Lucene.Net.Tests/Index/TestSizeBoundedForceMerge.cs new file mode 100644 index 0000000..812e759 --- /dev/null +++ b/src/Lucene.Net.Tests/Index/TestSizeBoundedForceMerge.cs @@ -0,0 +1,403 @@ +using Lucene.Net.Documents; + +namespace Lucene.Net.Index +{ + using NUnit.Framework; + using Directory = Lucene.Net.Store.Directory; + + /* + * 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 Document = Documents.Document; + using Field = Field; + using LuceneTestCase = Lucene.Net.Util.LuceneTestCase; + using RAMDirectory = Lucene.Net.Store.RAMDirectory; + using StringField = StringField; + + [TestFixture] + public class TestSizeBoundedForceMerge : LuceneTestCase + { + private void AddDocs(IndexWriter writer, int numDocs) + { + AddDocs(writer, numDocs, false); + } + + private void AddDocs(IndexWriter writer, int numDocs, bool withID) + { + for (int i = 0; i < numDocs; i++) + { + Document doc = new Document(); + if (withID) + { + doc.Add(new StringField("id", "" + i, Field.Store.NO)); + } + writer.AddDocument(doc); + } + writer.Commit(); + } + + private IndexWriterConfig NewWriterConfig() + { + IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null); + conf.SetMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH); + conf.SetRAMBufferSizeMB(IndexWriterConfig.DEFAULT_RAM_BUFFER_SIZE_MB); + // prevent any merges by default. + conf.SetMergePolicy(NoMergePolicy.COMPOUND_FILES); + return conf; + } + + [Test] + public virtual void TestByteSizeLimit() + { + // tests that the max merge size constraint is applied during forceMerge. + Directory dir = new RAMDirectory(); + + // Prepare an index w/ several small segments and a large one. + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + const int numSegments = 15; + for (int i = 0; i < numSegments; i++) + { + int numDocs = i == 7 ? 30 : 1; + AddDocs(writer, numDocs); + } + writer.Dispose(); + + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + double min = sis.Info(0).SizeInBytes(); + + conf = NewWriterConfig(); + LogByteSizeMergePolicy lmp = new LogByteSizeMergePolicy(); + lmp.MaxMergeMBForForcedMerge = (min + 1) / (1 << 20); + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + // Should only be 3 segments in the index, because one of them exceeds the size limit + sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(3, sis.Count); + } + + [Test] + public virtual void TestNumDocsLimit() + { + // tests that the max merge docs constraint is applied during forceMerge. + Directory dir = new RAMDirectory(); + + // Prepare an index w/ several small segments and a large one. + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 5); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + // Should only be 3 segments in the index, because one of them exceeds the size limit + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(3, sis.Count); + } + + [Test] + public virtual void TestLastSegmentTooLarge() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 5); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(2, sis.Count); + } + + [Test] + public virtual void TestFirstSegmentTooLarge() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 5); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(2, sis.Count); + } + + [Test] + public virtual void TestAllSegmentsSmall() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(1, sis.Count); + } + + [Test] + public virtual void TestAllSegmentsLarge() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 2; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(3, sis.Count); + } + + [Test] + public virtual void TestOneLargeOneSmall() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 5); + AddDocs(writer, 3); + AddDocs(writer, 5); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(4, sis.Count); + } + + [Test] + public virtual void TestMergeFactor() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 3); + AddDocs(writer, 5); + AddDocs(writer, 3); + AddDocs(writer, 3); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + lmp.MergeFactor = 2; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + // Should only be 4 segments in the index, because of the merge factor and + // max merge docs settings. + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(4, sis.Count); + } + + [Test] + public virtual void TestSingleMergeableSegment() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3); + AddDocs(writer, 5); + AddDocs(writer, 3); + + // delete the last document, so that the last segment is merged. + writer.DeleteDocuments(new Term("id", "10")); + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + // Verify that the last segment does not have deletions. + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(3, sis.Count); + Assert.IsFalse(sis.Info(2).HasDeletions); + } + + [Test] + public virtual void TestSingleNonMergeableSegment() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 3, true); + + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 3; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + // Verify that the last segment does not have deletions. + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(1, sis.Count); + } + + [Test] + public virtual void TestSingleMergeableTooLargeSegment() + { + Directory dir = new RAMDirectory(); + + IndexWriterConfig conf = NewWriterConfig(); + IndexWriter writer = new IndexWriter(dir, conf); + + AddDocs(writer, 5, true); + + // delete the last document + + writer.DeleteDocuments(new Term("id", "4")); + writer.Dispose(); + + conf = NewWriterConfig(); + LogMergePolicy lmp = new LogDocMergePolicy(); + lmp.MaxMergeDocs = 2; + conf.SetMergePolicy(lmp); + + writer = new IndexWriter(dir, conf); + writer.ForceMerge(1); + writer.Dispose(); + + // Verify that the last segment does not have deletions. + SegmentInfos sis = new SegmentInfos(); + sis.Read(dir); + Assert.AreEqual(1, sis.Count); + Assert.IsTrue(sis.Info(0).HasDeletions); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs new file mode 100644 index 0000000..3fb56f6 --- /dev/null +++ b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs @@ -0,0 +1,527 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Lucene.Net.Documents; + +namespace Lucene.Net.Index +{ + using Lucene.Net.Support; + using NUnit.Framework; + using Directory = Lucene.Net.Store.Directory; + using Document = Documents.Document; + using FieldType = FieldType; + using IndexInput = Lucene.Net.Store.IndexInput; + using LuceneTestCase = Lucene.Net.Util.LuceneTestCase; + + /* + * 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 MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer; + using TextField = TextField; + + // + // this was developed for Lucene In Action, + // http://lucenebook.com + // + [TestFixture] + public class TestSnapshotDeletionPolicy : LuceneTestCase + { + public const string INDEX_PATH = "test.snapshots"; + + protected internal virtual IndexWriterConfig GetConfig(Random random, IndexDeletionPolicy dp) + { + IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)); + if (dp != null) + { + conf.SetIndexDeletionPolicy(dp); + } + return conf; + } + + protected internal virtual void CheckSnapshotExists(Directory dir, IndexCommit c) + { + string segFileName = c.SegmentsFileName; + Assert.IsTrue(SlowFileExists(dir, segFileName), "segments file not found in directory: " + segFileName); + } + + protected internal virtual void CheckMaxDoc(IndexCommit commit, int expectedMaxDoc) + { + IndexReader reader = DirectoryReader.Open(commit); + try + { + Assert.AreEqual(expectedMaxDoc, reader.MaxDoc); + } + finally + { + reader.Dispose(); + } + } + + protected internal virtual void PrepareIndexAndSnapshots(SnapshotDeletionPolicy sdp, IndexWriter writer, int numSnapshots) + { + for (int i = 0; i < numSnapshots; i++) + { + // create dummy document to trigger commit. + writer.AddDocument(new Document()); + writer.Commit(); + Snapshots.Add(sdp.Snapshot()); + } + } + + protected internal virtual SnapshotDeletionPolicy DeletionPolicy + { + get + { + return new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy()); + } + } + + protected internal virtual void AssertSnapshotExists(Directory dir, SnapshotDeletionPolicy sdp, int numSnapshots, bool checkIndexCommitSame) + { + for (int i = 0; i < numSnapshots; i++) + { + IndexCommit snapshot = Snapshots[i]; + CheckMaxDoc(snapshot, i + 1); + CheckSnapshotExists(dir, snapshot); + if (checkIndexCommitSame) + { + Assert.AreSame(snapshot, sdp.GetIndexCommit(snapshot.Generation)); + } + else + { + Assert.AreEqual(snapshot.Generation, sdp.GetIndexCommit(snapshot.Generation).Generation); + } + } + } + + protected internal IList<IndexCommit> Snapshots; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + this.Snapshots = new List<IndexCommit>(); + } + + [Test] + public virtual void TestSnapshotDeletionPolicy_Mem() + { + Directory fsDir = NewDirectory(); + RunTest(Random(), fsDir); + fsDir.Dispose(); + } + + private void RunTest(Random random, Directory dir) + { + // Run for ~1 seconds + long stopTime = Environment.TickCount + 1000; + + SnapshotDeletionPolicy dp = DeletionPolicy; + IndexWriter writer = new IndexWriter(dir, (IndexWriterConfig)NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).SetIndexDeletionPolicy(dp).SetMaxBufferedDocs(2)); + + // Verify we catch misuse: + try + { + dp.Snapshot(); + Assert.Fail("did not hit exception"); + } +#pragma warning disable 168 + catch (InvalidOperationException ise) +#pragma warning restore 168 + { + // expected + } + dp = (SnapshotDeletionPolicy)writer.Config.IndexDeletionPolicy; + writer.Commit(); + + ThreadClass t = new ThreadAnonymousInnerClassHelper(stopTime, writer, NewField); + + t.Start(); + + // While the above indexing thread is running, take many + // backups: + do + { + BackupIndex(dir, dp); + Thread.Sleep(20); + } while (t.IsAlive); + + t.Join(); + + // Add one more document to force writer to commit a + // final segment, so deletion policy has a chance to + // delete again: + Document doc = new Document(); + FieldType customType = new FieldType(TextField.TYPE_STORED); + customType.StoreTermVectors = true; + customType.StoreTermVectorPositions = true; + customType.StoreTermVectorOffsets = true; + doc.Add(NewField("content", "aaa", customType)); + writer.AddDocument(doc); + + // Make sure we don't have any leftover files in the + // directory: + writer.Dispose(); + TestIndexWriter.AssertNoUnreferencedFiles(dir, "some files were not deleted but should have been"); + } + + private class ThreadAnonymousInnerClassHelper : ThreadClass + { + private long StopTime; + private IndexWriter Writer; + private readonly Func<string, string, FieldType, Field> _newFieldFunc; + + /// <param name="newFieldFunc"> + /// LUCENENET specific + /// Passed in because <see cref="LuceneTestCase.NewField(string, string, FieldType)"/> + /// is no longer static. + /// </param> + public ThreadAnonymousInnerClassHelper(long stopTime, IndexWriter writer, Func<string, string, FieldType, Field> newFieldFunc) + { + this.StopTime = stopTime; + this.Writer = writer; + _newFieldFunc = newFieldFunc; + } + + public override void Run() + { + Document doc = new Document(); + FieldType customType = new FieldType(TextField.TYPE_STORED); + customType.StoreTermVectors = true; + customType.StoreTermVectorPositions = true; + customType.StoreTermVectorOffsets = true; + doc.Add(_newFieldFunc("content", "aaa", customType)); + do + { + for (int i = 0; i < 27; i++) + { + try + { + Writer.AddDocument(doc); + } + catch (Exception t) + { + Console.WriteLine(t.StackTrace); + Assert.Fail("addDocument failed"); + } + if (i % 2 == 0) + { + try + { + Writer.Commit(); + } + catch (Exception e) + { + throw new Exception(e.Message, e); + } + } + } +#if !NETSTANDARD + try + { +#endif + Thread.Sleep(1); +#if !NETSTANDARD + } + catch (ThreadInterruptedException ie) + { + throw new ThreadInterruptedException("Thread Interrupted Exception", ie); + } +#endif + } while (Environment.TickCount < StopTime); + } + } + + /// <summary> + /// Example showing how to use the SnapshotDeletionPolicy to take a backup. + /// this method does not really do a backup; instead, it reads every byte of + /// every file just to test that the files indeed exist and are readable even + /// while the index is changing. + /// </summary> + public virtual void BackupIndex(Directory dir, SnapshotDeletionPolicy dp) + { + // To backup an index we first take a snapshot: + IndexCommit snapshot = dp.Snapshot(); + try + { + CopyFiles(dir, snapshot); + } + finally + { + // Make sure to release the snapshot, otherwise these + // files will never be deleted during this IndexWriter + // session: + dp.Release(snapshot); + } + } + + private void CopyFiles(Directory dir, IndexCommit cp) + { + // While we hold the snapshot, and nomatter how long + // we take to do the backup, the IndexWriter will + // never delete the files in the snapshot: + ICollection<string> files = cp.FileNames; + foreach (String fileName in files) + { + // NOTE: in a real backup you would not use + // readFile; you would need to use something else + // that copies the file to a backup location. this + // could even be a spawned shell process (eg "tar", + // "zip") that takes the list of files and builds a + // backup. + ReadFile(dir, fileName); + } + } + + internal byte[] Buffer = new byte[4096]; + + private void ReadFile(Directory dir, string name) + { + IndexInput input = dir.OpenInput(name, NewIOContext(Random())); + try + { + long size = dir.FileLength(name); + long bytesLeft = size; + while (bytesLeft > 0) + { + int numToRead; + if (bytesLeft < Buffer.Length) + { + numToRead = (int)bytesLeft; + } + else + { + numToRead = Buffer.Length; + } + input.ReadBytes(Buffer, 0, numToRead, false); + bytesLeft -= numToRead; + } + // Don't do this in your real backups! this is just + // to force a backup to take a somewhat long time, to + // make sure we are exercising the fact that the + // IndexWriter should not delete this file even when I + // take my time reading it. + Thread.Sleep(1); + } + finally + { + input.Dispose(); + } + } + + [Test] + public virtual void TestBasicSnapshots() + { + int numSnapshots = 3; + + // Create 3 snapshots: snapshot0, snapshot1, snapshot2 + Directory dir = NewDirectory(); + IndexWriter writer = new IndexWriter(dir, GetConfig(Random(), DeletionPolicy)); + SnapshotDeletionPolicy sdp = (SnapshotDeletionPolicy)writer.Config.IndexDeletionPolicy; + PrepareIndexAndSnapshots(sdp, writer, numSnapshots); + writer.Dispose(); + + Assert.AreEqual(numSnapshots, sdp.GetSnapshots().Count); + Assert.AreEqual(numSnapshots, sdp.SnapshotCount); + AssertSnapshotExists(dir, sdp, numSnapshots, true); + + // open a reader on a snapshot - should succeed. + DirectoryReader.Open(Snapshots[0]).Dispose(); + + // open a new IndexWriter w/ no snapshots to keep and assert that all snapshots are gone. + sdp = DeletionPolicy; + writer = new IndexWriter(dir, GetConfig(Random(), sdp)); + writer.DeleteUnusedFiles(); + writer.Dispose(); + Assert.AreEqual(1, DirectoryReader.ListCommits(dir).Count, "no snapshots should exist"); + dir.Dispose(); + } + + [Test] + public virtual void TestMultiThreadedSnapshotting() + { + Directory dir = NewDirectory(); + IndexWriter writer = new IndexWriter(dir, GetConfig(Random(), DeletionPolicy)); + SnapshotDeletionPolicy sdp = (SnapshotDeletionPolicy)writer.Config.IndexDeletionPolicy; + + ThreadClass[] threads = new ThreadClass[10]; + IndexCommit[] snapshots = new IndexCommit[threads.Length]; + for (int i = 0; i < threads.Length; i++) + { + int finalI = i; + threads[i] = new ThreadAnonymousInnerClassHelper2(this, writer, sdp, snapshots, finalI); + threads[i].Name = "t" + i; + } + + foreach (ThreadClass t in threads) + { + t.Start(); + } + + foreach (ThreadClass t in threads) + { + t.Join(); + } + + // Do one last commit, so that after we release all snapshots, we stay w/ one commit + writer.AddDocument(new Document()); + writer.Commit(); + + for (int i = 0; i < threads.Length; i++) + { + sdp.Release(snapshots[i]); + writer.DeleteUnusedFiles(); + } + Assert.AreEqual(1, DirectoryReader.ListCommits(dir).Count); + writer.Dispose(); + dir.Dispose(); + } + + private class ThreadAnonymousInnerClassHelper2 : ThreadClass + { + private readonly TestSnapshotDeletionPolicy OuterInstance; + + private IndexWriter Writer; + private SnapshotDeletionPolicy Sdp; + private IndexCommit[] Snapshots; + private int FinalI; + + public ThreadAnonymousInnerClassHelper2(TestSnapshotDeletionPolicy outerInstance, IndexWriter writer, SnapshotDeletionPolicy sdp, IndexCommit[] snapshots, int finalI) + { + this.OuterInstance = outerInstance; + this.Writer = writer; + this.Sdp = sdp; + this.Snapshots = snapshots; + this.FinalI = finalI; + } + + public override void Run() + { + try + { + Writer.AddDocument(new Document()); + Writer.Commit(); + Snapshots[FinalI] = Sdp.Snapshot(); + } + catch (Exception e) + { + throw new Exception(e.Message, e); + } + } + } + + [Test] + public virtual void TestRollbackToOldSnapshot() + { + int numSnapshots = 2; + Directory dir = NewDirectory(); + + SnapshotDeletionPolicy sdp = DeletionPolicy; + IndexWriter writer = new IndexWriter(dir, GetConfig(Random(), sdp)); + PrepareIndexAndSnapshots(sdp, writer, numSnapshots); + writer.Dispose(); + + // now open the writer on "snapshot0" - make sure it succeeds + writer = new IndexWriter(dir, GetConfig(Random(), sdp).SetIndexCommit(Snapshots[0])); + // this does the actual rollback + writer.Commit(); + writer.DeleteUnusedFiles(); + AssertSnapshotExists(dir, sdp, numSnapshots - 1, false); + writer.Dispose(); + + // but 'snapshot1' files will still exist (need to release snapshot before they can be deleted). + string segFileName = Snapshots[1].SegmentsFileName; + Assert.IsTrue(SlowFileExists(dir, segFileName), "snapshot files should exist in the directory: " + segFileName); + + dir.Dispose(); + } + + [Test] + public virtual void TestReleaseSnapshot() + { + Directory dir = NewDirectory(); + IndexWriter writer = new IndexWriter(dir, GetConfig(Random(), DeletionPolicy)); + SnapshotDeletionPolicy sdp = (SnapshotDeletionPolicy)writer.Config.IndexDeletionPolicy; + PrepareIndexAndSnapshots(sdp, writer, 1); + + // Create another commit - we must do that, because otherwise the "snapshot" + // files will still remain in the index, since it's the last commit. + writer.AddDocument(new Document()); + writer.Commit(); + + // Release + string segFileName = Snapshots[0].SegmentsFileName; + sdp.Release(Snapshots[0]); + writer.DeleteUnusedFiles(); + writer.Dispose(); + Assert.IsFalse(SlowFileExists(dir, segFileName), "segments file should not be found in dirctory: " + segFileName); + dir.Dispose(); + } + + [Test] + public virtual void TestSnapshotLastCommitTwice() + { + Directory dir = NewDirectory(); + + IndexWriter writer = new IndexWriter(dir, GetConfig(Random(), DeletionPolicy)); + SnapshotDeletionPolicy sdp = (SnapshotDeletionPolicy)writer.Config.IndexDeletionPolicy; + writer.AddDocument(new Document()); + writer.Commit(); + + IndexCommit s1 = sdp.Snapshot(); + IndexCommit s2 = sdp.Snapshot(); + Assert.AreSame(s1, s2); // should be the same instance + + // create another commit + writer.AddDocument(new Document()); + writer.Commit(); + + // release "s1" should not delete "s2" + sdp.Release(s1); + writer.DeleteUnusedFiles(); + CheckSnapshotExists(dir, s2); + + writer.Dispose(); + dir.Dispose(); + } + + [Test] + public virtual void TestMissingCommits() + { + // Tests the behavior of SDP when commits that are given at ctor are missing + // on onInit(). + Directory dir = NewDirectory(); + IndexWriter writer = new IndexWriter(dir, GetConfig(Random(), DeletionPolicy)); + SnapshotDeletionPolicy sdp = (SnapshotDeletionPolicy)writer.Config.IndexDeletionPolicy; + writer.AddDocument(new Document()); + writer.Commit(); + IndexCommit s1 = sdp.Snapshot(); + + // create another commit, not snapshotted. + writer.AddDocument(new Document()); + writer.Dispose(); + + // open a new writer w/ KeepOnlyLastCommit policy, so it will delete "s1" + // commit. + (new IndexWriter(dir, GetConfig(Random(), null))).Dispose(); + + Assert.IsFalse(SlowFileExists(dir, s1.SegmentsFileName), "snapshotted commit should not exist"); + dir.Dispose(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestStoredFieldsFormat.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Index/TestStoredFieldsFormat.cs b/src/Lucene.Net.Tests/Index/TestStoredFieldsFormat.cs new file mode 100644 index 0000000..9c551f3 --- /dev/null +++ b/src/Lucene.Net.Tests/Index/TestStoredFieldsFormat.cs @@ -0,0 +1,141 @@ +using Lucene.Net.Attributes; +using NUnit.Framework; + +namespace Lucene.Net.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. + */ + + using Codec = Lucene.Net.Codecs.Codec; + using Lucene3xCodec = Lucene.Net.Codecs.Lucene3x.Lucene3xCodec; + + /// <summary> + /// Tests with the default randomized codec. Not really redundant with + /// other specific instantiations since we want to test some test-only impls + /// like Asserting, as well as make it easy to write a codec and pass -Dtests.codec + /// </summary> + [TestFixture] + public class TestStoredFieldsFormat : BaseStoredFieldsFormatTestCase + { + protected override Codec Codec + { + get + { + return Codec.Default; + } + } + + [Test] + public override void TestWriteReadMerge() + { +#pragma warning disable 612, 618 + AssumeFalse("impersonation isnt good enough", Codec is Lucene3xCodec); +#pragma warning restore 612, 618 + // this test tries to switch up between the codec and another codec. + // for 3.x: we currently cannot take an index with existing 4.x segments + // and merge into newly formed 3.x segments. + base.TestWriteReadMerge(); + } + + + #region BaseStoredFieldsFormatTestCase + // LUCENENET NOTE: Tests in an abstract base class are not pulled into the correct + // context in Visual Studio. This fixes that with the minimum amount of code necessary + // to run them in the correct context without duplicating all of the tests. + + [Test] + public override void TestRandomStoredFields() + { + base.TestRandomStoredFields(); + } + + [Test] + // LUCENE-1727: make sure doc fields are stored in order + public override void TestStoredFieldsOrder() + { + base.TestStoredFieldsOrder(); + } + + [Test] + // LUCENE-1219 + public override void TestBinaryFieldOffsetLength() + { + base.TestBinaryFieldOffsetLength(); + } + + [Test] + public override void TestNumericField() + { + base.TestNumericField(); + } + + [Test] + public override void TestIndexedBit() + { + base.TestIndexedBit(); + } + + [Test] + public override void TestReadSkip() + { + base.TestReadSkip(); + } + + [Test] + public override void TestEmptyDocs() + { + base.TestEmptyDocs(); + } + + [Test] + public override void TestConcurrentReads() + { + base.TestConcurrentReads(); + } + +#if !NETSTANDARD + // LUCENENET: There is no Timeout on NUnit for .NET Core. + [Timeout(120000)] +#endif + [Test, HasTimeout] + public override void TestBigDocuments() + { + base.TestBigDocuments(); + } + + [Test] + public override void TestBulkMergeWithDeletes() + { + base.TestBulkMergeWithDeletes(); + } + + #endregion + + #region BaseIndexFileFormatTestCase + // LUCENENET NOTE: Tests in an abstract base class are not pulled into the correct + // context in Visual Studio. This fixes that with the minimum amount of code necessary + // to run them in the correct context without duplicating all of the tests. + + [Test] + public override void TestMergeStability() + { + base.TestMergeStability(); + } + + #endregion + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestStressAdvance.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Index/TestStressAdvance.cs b/src/Lucene.Net.Tests/Index/TestStressAdvance.cs new file mode 100644 index 0000000..c6c4521 --- /dev/null +++ b/src/Lucene.Net.Tests/Index/TestStressAdvance.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using Lucene.Net.Documents; + +namespace Lucene.Net.Index +{ + + using Lucene.Net.Store; + + /* + * 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 Lucene.Net.Util; + using NUnit.Framework; + using DocIdSetIterator = Lucene.Net.Search.DocIdSetIterator; + + [TestFixture] + public class TestStressAdvance : LuceneTestCase + { + [Test] + public virtual void TestStressAdvance_Mem() + { + for (int iter = 0; iter < 3; iter++) + { + if (VERBOSE) + { + Console.WriteLine("\nTEST: iter=" + iter); + } + Directory dir = NewDirectory(); + RandomIndexWriter w = new RandomIndexWriter(Random(), dir, Similarity, TimeZone); + HashSet<int> aDocs = new HashSet<int>(); + Documents.Document doc = new Documents.Document(); + Field f = NewStringField("field", "", Field.Store.NO); + doc.Add(f); + Field idField = NewStringField("id", "", Field.Store.YES); + doc.Add(idField); + int num = AtLeast(4097); + if (VERBOSE) + { + Console.WriteLine("\nTEST: numDocs=" + num); + } + for (int id = 0; id < num; id++) + { + if (Random().Next(4) == 3) + { + f.SetStringValue("a"); + aDocs.Add(id); + } + else + { + f.SetStringValue("b"); + } + idField.SetStringValue("" + id); + w.AddDocument(doc); + if (VERBOSE) + { + Console.WriteLine("\nTEST: doc upto " + id); + } + } + + w.ForceMerge(1); + + IList<int> aDocIDs = new List<int>(); + IList<int> bDocIDs = new List<int>(); + + DirectoryReader r = w.Reader; + int[] idToDocID = new int[r.MaxDoc]; + for (int docID = 0; docID < idToDocID.Length; docID++) + { + int id = Convert.ToInt32(r.Document(docID).Get("id")); + if (aDocs.Contains(id)) + { + aDocIDs.Add(docID); + } + else + { + bDocIDs.Add(docID); + } + } + TermsEnum te = GetOnlySegmentReader(r).Fields.GetTerms("field").GetIterator(null); + + DocsEnum de = null; + for (int iter2 = 0; iter2 < 10; iter2++) + { + if (VERBOSE) + { + Console.WriteLine("\nTEST: iter=" + iter + " iter2=" + iter2); + } + Assert.AreEqual(TermsEnum.SeekStatus.FOUND, te.SeekCeil(new BytesRef("a"))); + de = TestUtil.Docs(Random(), te, null, de, DocsEnum.FLAG_NONE); + TestOne(de, aDocIDs); + + Assert.AreEqual(TermsEnum.SeekStatus.FOUND, te.SeekCeil(new BytesRef("b"))); + de = TestUtil.Docs(Random(), te, null, de, DocsEnum.FLAG_NONE); + TestOne(de, bDocIDs); + } + + w.Dispose(); + r.Dispose(); + dir.Dispose(); + } + } + + private void TestOne(DocsEnum docs, IList<int> expected) + { + if (VERBOSE) + { + Console.WriteLine("test"); + } + int upto = -1; + while (upto < expected.Count) + { + if (VERBOSE) + { + Console.WriteLine(" cycle upto=" + upto + " of " + expected.Count); + } + int docID; + if (Random().Next(4) == 1 || upto == expected.Count - 1) + { + // test nextDoc() + if (VERBOSE) + { + Console.WriteLine(" do nextDoc"); + } + upto++; + docID = docs.NextDoc(); + } + else + { + // test advance() + int inc = TestUtil.NextInt(Random(), 1, expected.Count - 1 - upto); + if (VERBOSE) + { + Console.WriteLine(" do advance inc=" + inc); + } + upto += inc; + docID = docs.Advance(expected[upto]); + } + if (upto == expected.Count) + { + if (VERBOSE) + { + Console.WriteLine(" expect docID=" + DocIdSetIterator.NO_MORE_DOCS + " actual=" + docID); + } + Assert.AreEqual(DocIdSetIterator.NO_MORE_DOCS, docID); + } + else + { + if (VERBOSE) + { + Console.WriteLine(" expect docID=" + expected[upto] + " actual=" + docID); + } + Assert.IsTrue(docID != DocIdSetIterator.NO_MORE_DOCS); + Assert.AreEqual((int)expected[upto], docID); + } + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestStressIndexing.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Index/TestStressIndexing.cs b/src/Lucene.Net.Tests/Index/TestStressIndexing.cs new file mode 100644 index 0000000..428a2d0 --- /dev/null +++ b/src/Lucene.Net.Tests/Index/TestStressIndexing.cs @@ -0,0 +1,237 @@ +using System; +using System.Threading; +using Lucene.Net.Attributes; +using Lucene.Net.Documents; + +namespace Lucene.Net.Index +{ + + using Lucene.Net.Search; + using Lucene.Net.Store; + using Lucene.Net.Support; + + /* + /// Copyright 2004 The Apache Software Foundation + /// + /// Licensed 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 Lucene.Net.Util; + using NUnit.Framework; + using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer; + + [TestFixture] + public class TestStressIndexing : LuceneTestCase + { + private abstract class TimedThread : ThreadClass + { + internal volatile bool Failed; + internal int Count; + internal static int RUN_TIME_MSEC = AtLeast(1000); + internal TimedThread[] AllThreads; + + public abstract void DoWork(); + + internal TimedThread(TimedThread[] threads) + { + this.AllThreads = threads; + } + + public override void Run() + { + long stopTime = Environment.TickCount + RUN_TIME_MSEC; + + Count = 0; + + try + { + do + { + if (AnyErrors()) + { + break; + } + DoWork(); + Count++; + } while (Environment.TickCount < stopTime); + } + catch (Exception e) + { + Console.WriteLine(Thread.CurrentThread + ": exc"); + Console.WriteLine(e.StackTrace); + Failed = true; + } + } + + internal virtual bool AnyErrors() + { + for (int i = 0; i < AllThreads.Length; i++) + { + if (AllThreads[i] != null && AllThreads[i].Failed) + { + return true; + } + } + return false; + } + } + + private class IndexerThread : TimedThread + { + private readonly Func<string, string, Field.Store, Field> NewStringFieldFunc; + private readonly Func<string, string, Field.Store, Field> NewTextFieldFunc; + + internal IndexWriter Writer; + internal int NextID; + + /// <param name="newStringField"> + /// LUCENENET specific + /// Passed in because <see cref="LuceneTestCase.NewStringField(string, string, Field.Store)"/> + /// is no longer static. + /// </param> + /// <param name="newTextField"> + /// LUCENENET specific + /// Passed in because <see cref="LuceneTestCase.NewTextField(string, string, Field.Store)"/> + /// is no longer static. + /// </param> + public IndexerThread(IndexWriter writer, TimedThread[] threads, + Func<string, string, Field.Store, Field> newStringField, + Func<string, string, Field.Store, Field> newTextField) + : base(threads) + { + this.Writer = writer; + NewStringFieldFunc = newStringField; + NewTextFieldFunc = newTextField; + } + + public override void DoWork() + { + // Add 10 docs: + for (int j = 0; j < 10; j++) + { + Documents.Document d = new Documents.Document(); + int n = Random().Next(); + d.Add(NewStringFieldFunc("id", Convert.ToString(NextID++), Field.Store.YES)); + d.Add(NewTextFieldFunc("contents", English.IntToEnglish(n), Field.Store.NO)); + Writer.AddDocument(d); + } + + // Delete 5 docs: + int deleteID = NextID - 1; + for (int j = 0; j < 5; j++) + { + Writer.DeleteDocuments(new Term("id", "" + deleteID)); + deleteID -= 2; + } + } + } + + private class SearcherThread : TimedThread + { + internal Directory Directory; + private readonly LuceneTestCase OuterInstance; + + /// <param name="outerInstance"> + /// LUCENENET specific + /// Passed in because <see cref="LuceneTestCase.NewSearcher(IndexReader)"/> + /// is no longer static. + /// </param> + public SearcherThread(Directory directory, TimedThread[] threads, LuceneTestCase outerInstance) + : base(threads) + { + OuterInstance = outerInstance; + this.Directory = directory; + } + + public override void DoWork() + { + for (int i = 0; i < 100; i++) + { + IndexReader ir = DirectoryReader.Open(Directory); + IndexSearcher @is = OuterInstance.NewSearcher(ir); + ir.Dispose(); + } + Count += 100; + } + } + + /* + Run one indexer and 2 searchers against single index as + stress test. + */ + + public virtual void RunStressTest(Directory directory, IConcurrentMergeScheduler mergeScheduler) + { + IndexWriter modifier = new IndexWriter(directory, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetOpenMode(OpenMode.CREATE).SetMaxBufferedDocs(10).SetMergeScheduler(mergeScheduler)); + modifier.Commit(); + + TimedThread[] threads = new TimedThread[4]; + int numThread = 0; + + // One modifier that writes 10 docs then removes 5, over + // and over: + IndexerThread indexerThread = new IndexerThread(modifier, threads, NewStringField, NewTextField); + threads[numThread++] = indexerThread; + indexerThread.Start(); + + IndexerThread indexerThread2 = new IndexerThread(modifier, threads, NewStringField, NewTextField); + threads[numThread++] = indexerThread2; + indexerThread2.Start(); + + // Two searchers that constantly just re-instantiate the + // searcher: + SearcherThread searcherThread1 = new SearcherThread(directory, threads, this); + threads[numThread++] = searcherThread1; + searcherThread1.Start(); + + SearcherThread searcherThread2 = new SearcherThread(directory, threads, this); + threads[numThread++] = searcherThread2; + searcherThread2.Start(); + + for (int i = 0; i < numThread; i++) + { + threads[i].Join(); + } + + modifier.Dispose(); + + for (int i = 0; i < numThread; i++) + { + Assert.IsTrue(!threads[i].Failed); + } + + //System.out.println(" Writer: " + indexerThread.count + " iterations"); + //System.out.println("Searcher 1: " + searcherThread1.count + " searchers created"); + //System.out.println("Searcher 2: " + searcherThread2.count + " searchers created"); + } + + /* + Run above stress test against RAMDirectory and then + FSDirectory. + */ + + [Test] + public virtual void TestStressIndexAndSearching([ValueSource(typeof(ConcurrentMergeSchedulers), "Values")]IConcurrentMergeScheduler scheduler) + { + Directory directory = NewDirectory(); + MockDirectoryWrapper wrapper = directory as MockDirectoryWrapper; + if (wrapper != null) + { + wrapper.AssertNoUnrefencedFilesOnClose = true; + } + + RunStressTest(directory, scheduler); + directory.Dispose(); + } + } +} \ No newline at end of file
