lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nightowl...@apache.org
Subject [30/72] [abbrv] [partial] lucenenet git commit: Lucene.Net.Tests: Removed \core directory and put its contents in root directory
Date Sun, 26 Feb 2017 23:37:18 GMT
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Index/TestIndexWriterDelete.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterDelete.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterDelete.cs
new file mode 100644
index 0000000..6ac040a
--- /dev/null
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterDelete.cs
@@ -0,0 +1,1447 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+using Lucene.Net.Attributes;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Index
+{
+    using Lucene.Net.Randomized.Generators;
+    using Lucene.Net.Support;
+    using NUnit.Framework;
+    using System.IO;
+    using Util;
+    /*
+         * 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 Analyzer = Lucene.Net.Analysis.Analyzer;
+    using Directory = Lucene.Net.Store.Directory;
+    using Document = Documents.Document;
+    using Field = Field;
+    using FieldType = FieldType;
+    using IndexSearcher = Lucene.Net.Search.IndexSearcher;
+    using IOUtils = Lucene.Net.Util.IOUtils;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using MockDirectoryWrapper = Lucene.Net.Store.MockDirectoryWrapper;
+    using MockTokenizer = Lucene.Net.Analysis.MockTokenizer;
+    using NumericDocValuesField = NumericDocValuesField;
+    using RAMDirectory = Lucene.Net.Store.RAMDirectory;
+    using ScoreDoc = Lucene.Net.Search.ScoreDoc;
+    using StringField = StringField;
+    using TermQuery = Lucene.Net.Search.TermQuery;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+
+    [TestFixture]
+    public class TestIndexWriterDelete : LuceneTestCase
+    {
+        // test the simple case
+        [Test]
+        public virtual void TestSimpleCase()
+        {
+            string[] keywords = new string[] { "1", "2" };
+            string[] unindexed = new string[] { "Netherlands", "Italy" };
+            string[] unstored = new string[] { "Amsterdam has lots of bridges", "Venice has lots of canals" };
+            string[] text = new string[] { "Amsterdam", "Venice" };
+
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDeleteTerms(1));
+
+            FieldType custom1 = new FieldType();
+            custom1.IsStored = true;
+            for (int i = 0; i < keywords.Length; i++)
+            {
+                Document doc = new Document();
+                doc.Add(NewStringField("id", keywords[i], Field.Store.YES));
+                doc.Add(NewField("country", unindexed[i], custom1));
+                doc.Add(NewTextField("contents", unstored[i], Field.Store.NO));
+                doc.Add(NewTextField("city", text[i], Field.Store.YES));
+                modifier.AddDocument(doc);
+            }
+            modifier.ForceMerge(1);
+            modifier.Commit();
+
+            Term term = new Term("city", "Amsterdam");
+            int hitCount = GetHitCount(dir, term);
+            Assert.AreEqual(1, hitCount);
+            if (VERBOSE)
+            {
+                Console.WriteLine("\nTEST: now delete by term=" + term);
+            }
+            modifier.DeleteDocuments(term);
+            modifier.Commit();
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("\nTEST: now getHitCount");
+            }
+            hitCount = GetHitCount(dir, term);
+            Assert.AreEqual(0, hitCount);
+
+            modifier.Dispose();
+            dir.Dispose();
+        }
+
+        // test when delete terms only apply to disk segments
+        [Test]
+        public virtual void TestNonRAMDelete()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(2).SetMaxBufferedDeleteTerms(2));
+            int id = 0;
+            int value = 100;
+
+            for (int i = 0; i < 7; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.Commit();
+
+            Assert.AreEqual(0, modifier.NumBufferedDocuments);
+            Assert.IsTrue(0 < modifier.SegmentCount);
+
+            modifier.Commit();
+
+            IndexReader reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            modifier.DeleteDocuments(new Term("value", Convert.ToString(value)));
+
+            modifier.Commit();
+
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(0, reader.NumDocs);
+            reader.Dispose();
+            modifier.Dispose();
+            dir.Dispose();
+        }
+
+        [Test]
+        public virtual void TestMaxBufferedDeletes()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter writer = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDeleteTerms(1));
+
+            writer.AddDocument(new Document());
+            writer.DeleteDocuments(new Term("foobar", "1"));
+            writer.DeleteDocuments(new Term("foobar", "1"));
+            writer.DeleteDocuments(new Term("foobar", "1"));
+            Assert.AreEqual(3, writer.FlushDeletesCount);
+            writer.Dispose();
+            dir.Dispose();
+        }
+
+        // test when delete terms only apply to ram segments
+        [Test]
+        public virtual void TestRAMDeletes()
+        {
+            for (int t = 0; t < 2; t++)
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: t=" + t);
+                }
+                Directory dir = NewDirectory();
+                IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(4).SetMaxBufferedDeleteTerms(4));
+                int id = 0;
+                int value = 100;
+
+                AddDoc(modifier, ++id, value);
+                if (0 == t)
+                {
+                    modifier.DeleteDocuments(new Term("value", Convert.ToString(value)));
+                }
+                else
+                {
+                    modifier.DeleteDocuments(new TermQuery(new Term("value", Convert.ToString(value))));
+                }
+                AddDoc(modifier, ++id, value);
+                if (0 == t)
+                {
+                    modifier.DeleteDocuments(new Term("value", Convert.ToString(value)));
+                    Assert.AreEqual(2, modifier.NumBufferedDeleteTerms);
+                    Assert.AreEqual(1, modifier.BufferedDeleteTermsSize);
+                }
+                else
+                {
+                    modifier.DeleteDocuments(new TermQuery(new Term("value", Convert.ToString(value))));
+                }
+
+                AddDoc(modifier, ++id, value);
+                Assert.AreEqual(0, modifier.SegmentCount);
+                modifier.Commit();
+
+                IndexReader reader = DirectoryReader.Open(dir);
+                Assert.AreEqual(1, reader.NumDocs);
+
+                int hitCount = GetHitCount(dir, new Term("id", Convert.ToString(id)));
+                Assert.AreEqual(1, hitCount);
+                reader.Dispose();
+                modifier.Dispose();
+                dir.Dispose();
+            }
+        }
+
+        // test when delete terms apply to both disk and ram segments
+        [Test]
+        public virtual void TestBothDeletes()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(100).SetMaxBufferedDeleteTerms(100));
+
+            int id = 0;
+            int value = 100;
+
+            for (int i = 0; i < 5; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+
+            value = 200;
+            for (int i = 0; i < 5; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.Commit();
+
+            for (int i = 0; i < 5; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.DeleteDocuments(new Term("value", Convert.ToString(value)));
+
+            modifier.Commit();
+
+            IndexReader reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(5, reader.NumDocs);
+            modifier.Dispose();
+            reader.Dispose();
+            dir.Dispose();
+        }
+
+        // test that batched delete terms are flushed together
+        [Test]
+        public virtual void TestBatchDeletes()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(2).SetMaxBufferedDeleteTerms(2));
+
+            int id = 0;
+            int value = 100;
+
+            for (int i = 0; i < 7; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.Commit();
+
+            IndexReader reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            id = 0;
+            modifier.DeleteDocuments(new Term("id", Convert.ToString(++id)));
+            modifier.DeleteDocuments(new Term("id", Convert.ToString(++id)));
+
+            modifier.Commit();
+
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(5, reader.NumDocs);
+            reader.Dispose();
+
+            Term[] terms = new Term[3];
+            for (int i = 0; i < terms.Length; i++)
+            {
+                terms[i] = new Term("id", Convert.ToString(++id));
+            }
+            modifier.DeleteDocuments(terms);
+            modifier.Commit();
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(2, reader.NumDocs);
+            reader.Dispose();
+
+            modifier.Dispose();
+            dir.Dispose();
+        }
+
+        // test deleteAll()
+        [Test]
+        public virtual void TestDeleteAll()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, (IndexWriterConfig)NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(2).SetMaxBufferedDeleteTerms(2));
+
+            int id = 0;
+            int value = 100;
+
+            for (int i = 0; i < 7; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.Commit();
+
+            IndexReader reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            // Add 1 doc (so we will have something buffered)
+            AddDoc(modifier, 99, value);
+
+            // Delete all
+            modifier.DeleteAll();
+
+            // Delete all shouldn't be on disk yet
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            // Add a doc and update a doc (after the deleteAll, before the commit)
+            AddDoc(modifier, 101, value);
+            UpdateDoc(modifier, 102, value);
+
+            // commit the delete all
+            modifier.Commit();
+
+            // Validate there are no docs left
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(2, reader.NumDocs);
+            reader.Dispose();
+
+            modifier.Dispose();
+            dir.Dispose();
+        }
+
+        [Test]
+        public virtual void TestDeleteAllNoDeadLock()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter modifier = new RandomIndexWriter(Random(), dir, Similarity, TimeZone);
+            int numThreads = AtLeast(2);
+            ThreadClass[] threads = new ThreadClass[numThreads];
+            CountdownEvent latch = new CountdownEvent(1);
+            CountdownEvent doneLatch = new CountdownEvent(numThreads);
+            for (int i = 0; i < numThreads; i++)
+            {
+                int offset = i;
+                threads[i] = new ThreadAnonymousInnerClassHelper(this, modifier, latch, doneLatch, offset);
+                threads[i].Start();
+            }
+            latch.Signal();
+            //Wait for 1 millisecond
+            while (!doneLatch.Wait(new TimeSpan(0, 0, 0, 0, 1)))
+            {
+                modifier.DeleteAll();
+                if (VERBOSE)
+                {
+                    Console.WriteLine("del all");
+                }
+            }
+
+            modifier.DeleteAll();
+            foreach (ThreadClass thread in threads)
+            {
+                thread.Join();
+            }
+
+            modifier.Dispose();
+            DirectoryReader reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(reader.MaxDoc, 0);
+            Assert.AreEqual(reader.NumDocs, 0);
+            Assert.AreEqual(reader.NumDeletedDocs, 0);
+            reader.Dispose();
+
+            dir.Dispose();
+        }
+
+        private class ThreadAnonymousInnerClassHelper : ThreadClass
+        {
+            private readonly TestIndexWriterDelete OuterInstance;
+
+            private RandomIndexWriter Modifier;
+            private CountdownEvent Latch;
+            private CountdownEvent DoneLatch;
+            private int Offset;
+
+            public ThreadAnonymousInnerClassHelper(TestIndexWriterDelete outerInstance, RandomIndexWriter modifier, CountdownEvent latch, CountdownEvent doneLatch, int offset)
+            {
+                this.OuterInstance = outerInstance;
+                this.Modifier = modifier;
+                this.Latch = latch;
+                this.DoneLatch = doneLatch;
+                this.Offset = offset;
+            }
+
+            public override void Run()
+            {
+                int id = Offset * 1000;
+                int value = 100;
+                try
+                {
+                    Latch.Wait();
+                    for (int j = 0; j < 1000; j++)
+                    {
+                        Document doc = new Document();
+                        doc.Add(OuterInstance.NewTextField("content", "aaa", Field.Store.NO));
+                        doc.Add(OuterInstance.NewStringField("id", Convert.ToString(id++), Field.Store.YES));
+                        doc.Add(OuterInstance.NewStringField("value", Convert.ToString(value), Field.Store.NO));
+                        if (DefaultCodecSupportsDocValues())
+                        {
+                            doc.Add(new NumericDocValuesField("dv", value));
+                        }
+                        Modifier.AddDocument(doc);
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("\tThread[" + Offset + "]: add doc: " + id);
+                        }
+                    }
+                }
+                catch (Exception e)
+                {
+                    throw new Exception(e.Message, e);
+                }
+                finally
+                {
+                    DoneLatch.Signal();
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("\tThread[" + Offset + "]: done indexing");
+                    }
+                }
+            }
+        }
+
+        // test rollback of deleteAll()
+        [Test]
+        public virtual void TestDeleteAllRollback()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, (IndexWriterConfig)NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(2).SetMaxBufferedDeleteTerms(2));
+
+            int id = 0;
+            int value = 100;
+
+            for (int i = 0; i < 7; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.Commit();
+
+            AddDoc(modifier, ++id, value);
+
+            IndexReader reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            // Delete all
+            modifier.DeleteAll();
+
+            // Roll it back
+            modifier.Rollback();
+            modifier.Dispose();
+
+            // Validate that the docs are still there
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            dir.Dispose();
+        }
+
+        // test deleteAll() w/ near real-time reader
+        [Test]
+        public virtual void TestDeleteAllNRT()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, (IndexWriterConfig)NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDocs(2).SetMaxBufferedDeleteTerms(2));
+
+            int id = 0;
+            int value = 100;
+
+            for (int i = 0; i < 7; i++)
+            {
+                AddDoc(modifier, ++id, value);
+            }
+            modifier.Commit();
+
+            IndexReader reader = modifier.Reader;
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            AddDoc(modifier, ++id, value);
+            AddDoc(modifier, ++id, value);
+
+            // Delete all
+            modifier.DeleteAll();
+
+            reader = modifier.Reader;
+            Assert.AreEqual(0, reader.NumDocs);
+            reader.Dispose();
+
+            // Roll it back
+            modifier.Rollback();
+            modifier.Dispose();
+
+            // Validate that the docs are still there
+            reader = DirectoryReader.Open(dir);
+            Assert.AreEqual(7, reader.NumDocs);
+            reader.Dispose();
+
+            dir.Dispose();
+        }
+
+        private void UpdateDoc(IndexWriter modifier, int id, int value)
+        {
+            Document doc = new Document();
+            doc.Add(NewTextField("content", "aaa", Field.Store.NO));
+            doc.Add(NewStringField("id", Convert.ToString(id), Field.Store.YES));
+            doc.Add(NewStringField("value", Convert.ToString(value), Field.Store.NO));
+            if (DefaultCodecSupportsDocValues())
+            {
+                doc.Add(new NumericDocValuesField("dv", value));
+            }
+            modifier.UpdateDocument(new Term("id", Convert.ToString(id)), doc);
+        }
+
+        private void AddDoc(IndexWriter modifier, int id, int value)
+        {
+            Document doc = new Document();
+            doc.Add(NewTextField("content", "aaa", Field.Store.NO));
+            doc.Add(NewStringField("id", Convert.ToString(id), Field.Store.YES));
+            doc.Add(NewStringField("value", Convert.ToString(value), Field.Store.NO));
+            if (DefaultCodecSupportsDocValues())
+            {
+                doc.Add(new NumericDocValuesField("dv", value));
+            }
+            modifier.AddDocument(doc);
+        }
+
+        private int GetHitCount(Directory dir, Term term)
+        {
+            IndexReader reader = DirectoryReader.Open(dir);
+            IndexSearcher searcher = NewSearcher(reader);
+            int hitCount = searcher.Search(new TermQuery(term), null, 1000).TotalHits;
+            reader.Dispose();
+            return hitCount;
+        }
+
+        [Test]
+        public virtual void TestDeletesOnDiskFull(
+            [ValueSource(typeof(ConcurrentMergeSchedulers), "Values")]IConcurrentMergeScheduler scheduler)
+        {
+            DoTestOperationsOnDiskFull(scheduler, false);
+        }
+
+        [Test]
+        public virtual void TestUpdatesOnDiskFull(
+            [ValueSource(typeof(ConcurrentMergeSchedulers), "Values")]IConcurrentMergeScheduler scheduler)
+        {
+            DoTestOperationsOnDiskFull(scheduler, true);
+        }
+
+        /// <summary>
+        /// Make sure if modifier tries to commit but hits disk full that modifier
+        /// remains consistent and usable. Similar to TestIndexReader.testDiskFull().
+        /// </summary>
+        private void DoTestOperationsOnDiskFull(IConcurrentMergeScheduler scheduler, bool updates)
+        {
+            Term searchTerm = new Term("content", "aaa");
+            int START_COUNT = 157;
+            int END_COUNT = 144;
+
+            // First build up a starting index:
+            MockDirectoryWrapper startDir = NewMockDirectory();
+            // TODO: find the resource leak that only occurs sometimes here.
+            startDir.NoDeleteOpenFile = false;
+            IndexWriter writer = new IndexWriter(startDir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)));
+            for (int i = 0; i < 157; i++)
+            {
+                Document d = new Document();
+                d.Add(NewStringField("id", Convert.ToString(i), Field.Store.YES));
+                d.Add(NewTextField("content", "aaa " + i, Field.Store.NO));
+                if (DefaultCodecSupportsDocValues())
+                {
+                    d.Add(new NumericDocValuesField("dv", i));
+                }
+                writer.AddDocument(d);
+            }
+            writer.Dispose();
+
+            long diskUsage = startDir.SizeInBytes();
+            long diskFree = diskUsage + 10;
+
+            IOException err = null;
+
+            bool done = false;
+
+            // Iterate w/ ever increasing free disk space:
+            while (!done)
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: cycle");
+                }
+                MockDirectoryWrapper dir = new MockDirectoryWrapper(Random(), new RAMDirectory(startDir, NewIOContext(Random())));
+                dir.PreventDoubleWrite = false;
+                dir.AllowRandomFileNotFoundException = false;
+
+                var config = NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false))
+                                .SetMaxBufferedDocs(1000)
+                                .SetMaxBufferedDeleteTerms(1000)
+                                .SetMergeScheduler(scheduler);
+
+                scheduler.SetSuppressExceptions();
+
+                IndexWriter modifier = new IndexWriter(dir, config);
+
+                // For each disk size, first try to commit against
+                // dir that will hit random IOExceptions & disk
+                // full; after, give it infinite disk space & turn
+                // off random IOExceptions & retry w/ same reader:
+                bool success = false;
+
+                for (int x = 0; x < 2; x++)
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST: x=" + x);
+                    }
+
+                    double rate = 0.1;
+                    double diskRatio = ((double)diskFree) / diskUsage;
+                    long thisDiskFree;
+                    string testName;
+
+                    if (0 == x)
+                    {
+                        thisDiskFree = diskFree;
+                        if (diskRatio >= 2.0)
+                        {
+                            rate /= 2;
+                        }
+                        if (diskRatio >= 4.0)
+                        {
+                            rate /= 2;
+                        }
+                        if (diskRatio >= 6.0)
+                        {
+                            rate = 0.0;
+                        }
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("\ncycle: " + diskFree + " bytes");
+                        }
+                        testName = "disk full during reader.Dispose() @ " + thisDiskFree + " bytes";
+                        dir.RandomIOExceptionRateOnOpen = Random().NextDouble() * 0.01;
+                    }
+                    else
+                    {
+                        thisDiskFree = 0;
+                        rate = 0.0;
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("\ncycle: same writer: unlimited disk space");
+                        }
+                        testName = "reader re-use after disk full";
+                        dir.RandomIOExceptionRateOnOpen = 0.0;
+                    }
+
+                    dir.MaxSizeInBytes = thisDiskFree;
+                    dir.RandomIOExceptionRate = rate;
+
+                    try
+                    {
+                        if (0 == x)
+                        {
+                            int docId = 12;
+                            for (int i = 0; i < 13; i++)
+                            {
+                                if (updates)
+                                {
+                                    Document d = new Document();
+                                    d.Add(NewStringField("id", Convert.ToString(i), Field.Store.YES));
+                                    d.Add(NewTextField("content", "bbb " + i, Field.Store.NO));
+                                    if (DefaultCodecSupportsDocValues())
+                                    {
+                                        d.Add(new NumericDocValuesField("dv", i));
+                                    }
+                                    modifier.UpdateDocument(new Term("id", Convert.ToString(docId)), d);
+                                } // deletes
+                                else
+                                {
+                                    modifier.DeleteDocuments(new Term("id", Convert.ToString(docId)));
+                                    // modifier.setNorm(docId, "contents", (float)2.0);
+                                }
+                                docId += 12;
+                            }
+                        }
+                        modifier.Dispose();
+                        success = true;
+                        if (0 == x)
+                        {
+                            done = true;
+                        }
+                    }
+                    catch (IOException e)
+                    {
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("  hit IOException: " + e);
+                            Console.WriteLine(e.StackTrace);
+                        }
+                        err = e;
+                        if (1 == x)
+                        {
+                            Console.WriteLine(e.ToString());
+                            Console.Write(e.StackTrace);
+                            Assert.Fail(testName + " hit IOException after disk space was freed up");
+                        }
+                    }
+                    // prevent throwing a random exception here!!
+                    double randomIOExceptionRate = dir.RandomIOExceptionRate;
+                    long maxSizeInBytes = dir.MaxSizeInBytes;
+                    dir.RandomIOExceptionRate = 0.0;
+                    dir.RandomIOExceptionRateOnOpen = 0.0;
+                    dir.MaxSizeInBytes = 0;
+                    if (!success)
+                    {
+                        // Must force the close else the writer can have
+                        // open files which cause exc in MockRAMDir.close
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TEST: now rollback");
+                        }
+                        modifier.Rollback();
+                    }
+
+                    // If the close() succeeded, make sure there are
+                    // no unreferenced files.
+                    if (success)
+                    {
+                        TestUtil.CheckIndex(dir);
+                        TestIndexWriter.AssertNoUnreferencedFiles(dir, "after writer.close");
+                    }
+                    dir.RandomIOExceptionRate = randomIOExceptionRate;
+                    dir.MaxSizeInBytes = maxSizeInBytes;
+
+                    // Finally, verify index is not corrupt, and, if
+                    // we succeeded, we see all docs changed, and if
+                    // we failed, we see either all docs or no docs
+                    // changed (transactional semantics):
+                    IndexReader newReader = null;
+                    try
+                    {
+                        newReader = DirectoryReader.Open(dir);
+                    }
+                    catch (IOException e)
+                    {
+                        Console.WriteLine(e.ToString());
+                        Console.Write(e.StackTrace);
+                        Assert.Fail(testName + ":exception when creating IndexReader after disk full during close: " + e);
+                    }
+
+                    IndexSearcher searcher = NewSearcher(newReader);
+                    ScoreDoc[] hits = null;
+                    try
+                    {
+                        hits = searcher.Search(new TermQuery(searchTerm), null, 1000).ScoreDocs;
+                    }
+                    catch (IOException e)
+                    {
+                        Console.WriteLine(e.ToString());
+                        Console.Write(e.StackTrace);
+                        Assert.Fail(testName + ": exception when searching: " + e);
+                    }
+                    int result2 = hits.Length;
+                    if (success)
+                    {
+                        if (x == 0 && result2 != END_COUNT)
+                        {
+                            Assert.Fail(testName + ": method did not throw exception but hits.Length for search on term 'aaa' is " + result2 + " instead of expected " + END_COUNT);
+                        }
+                        else if (x == 1 && result2 != START_COUNT && result2 != END_COUNT)
+                        {
+                            // It's possible that the first exception was
+                            // "recoverable" wrt pending deletes, in which
+                            // case the pending deletes are retained and
+                            // then re-flushing (with plenty of disk
+                            // space) will succeed in flushing the
+                            // deletes:
+                            Assert.Fail(testName + ": method did not throw exception but hits.Length for search on term 'aaa' is " + result2 + " instead of expected " + START_COUNT + " or " + END_COUNT);
+                        }
+                    }
+                    else
+                    {
+                        // On hitting exception we still may have added
+                        // all docs:
+                        if (result2 != START_COUNT && result2 != END_COUNT)
+                        {
+                            Console.WriteLine(err.ToString());
+                            Console.Write(err.StackTrace);
+                            Assert.Fail(testName + ": method did throw exception but hits.Length for search on term 'aaa' is " + result2 + " instead of expected " + START_COUNT + " or " + END_COUNT);
+                        }
+                    }
+                    newReader.Dispose();
+                    if (result2 == END_COUNT)
+                    {
+                        break;
+                    }
+                }
+                dir.Dispose();
+                modifier.Dispose();
+
+                // Try again with 10 more bytes of free space:
+                diskFree += 10;
+            }
+            startDir.Dispose();
+        }
+
+        // this test tests that buffered deletes are cleared when
+        // an Exception is hit during flush.
+        [Test]
+        public virtual void TestErrorAfterApplyDeletes()
+        {
+            MockDirectoryWrapper.Failure failure = new FailureAnonymousInnerClassHelper(this);
+
+            // create a couple of files
+
+            string[] keywords = new string[] { "1", "2" };
+            string[] unindexed = new string[] { "Netherlands", "Italy" };
+            string[] unstored = new string[] { "Amsterdam has lots of bridges", "Venice has lots of canals" };
+            string[] text = new string[] { "Amsterdam", "Venice" };
+
+            MockDirectoryWrapper dir = NewMockDirectory();
+            IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)).SetMaxBufferedDeleteTerms(2).SetReaderPooling(false).SetMergePolicy(NewLogMergePolicy()));
+
+            MergePolicy lmp = modifier.Config.MergePolicy;
+            lmp.NoCFSRatio = 1.0;
+
+            dir.FailOn(failure.Reset());
+
+            FieldType custom1 = new FieldType();
+            custom1.IsStored = true;
+            for (int i = 0; i < keywords.Length; i++)
+            {
+                Document doc = new Document();
+                doc.Add(NewStringField("id", keywords[i], Field.Store.YES));
+                doc.Add(NewField("country", unindexed[i], custom1));
+                doc.Add(NewTextField("contents", unstored[i], Field.Store.NO));
+                doc.Add(NewTextField("city", text[i], Field.Store.YES));
+                modifier.AddDocument(doc);
+            }
+            // flush (and commit if ac)
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: now full merge");
+            }
+
+            modifier.ForceMerge(1);
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: now commit");
+            }
+            modifier.Commit();
+
+            // one of the two files hits
+
+            Term term = new Term("city", "Amsterdam");
+            int hitCount = GetHitCount(dir, term);
+            Assert.AreEqual(1, hitCount);
+
+            // open the writer again (closed above)
+
+            // delete the doc
+            // max buf del terms is two, so this is buffered
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: delete term=" + term);
+            }
+
+            modifier.DeleteDocuments(term);
+
+            // add a doc (needed for the !ac case; see below)
+            // doc remains buffered
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: add empty doc");
+            }
+            Document doc_ = new Document();
+            modifier.AddDocument(doc_);
+
+            // commit the changes, the buffered deletes, and the new doc
+
+            // The failure object will fail on the first write after the del
+            // file gets created when processing the buffered delete
+
+            // in the ac case, this will be when writing the new segments
+            // files so we really don't need the new doc, but it's harmless
+
+            // a new segments file won't be created but in this
+            // case, creation of the cfs file happens next so we
+            // need the doc (to test that it's okay that we don't
+            // lose deletes if failing while creating the cfs file)
+            bool failed = false;
+            try
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: now commit for failure");
+                }
+                modifier.Commit();
+            }
+#pragma warning disable 168
+            catch (IOException ioe)
+#pragma warning restore 168
+            {
+                // expected
+                failed = true;
+            }
+
+            Assert.IsTrue(failed);
+
+            // The commit above failed, so we need to retry it (which will
+            // succeed, because the failure is a one-shot)
+
+            modifier.Commit();
+
+            hitCount = GetHitCount(dir, term);
+
+            // Make sure the delete was successfully flushed:
+            Assert.AreEqual(0, hitCount);
+
+            modifier.Dispose();
+            dir.Dispose();
+        }
+
+        private class FailureAnonymousInnerClassHelper : MockDirectoryWrapper.Failure
+        {
+            private readonly TestIndexWriterDelete OuterInstance;
+
+            public FailureAnonymousInnerClassHelper(TestIndexWriterDelete outerInstance)
+            {
+                this.OuterInstance = outerInstance;
+                sawMaybe = false;
+                failed = false;
+            }
+
+            internal bool sawMaybe;
+            internal bool failed;
+            internal Thread thread;
+
+            public override MockDirectoryWrapper.Failure Reset()
+            {
+                thread = Thread.CurrentThread;
+                sawMaybe = false;
+                failed = false;
+                return this;
+            }
+
+            public override void Eval(MockDirectoryWrapper dir)
+            {
+                if (Thread.CurrentThread != thread)
+                {
+                    // don't fail during merging
+                    return;
+                }
+                if (sawMaybe && !failed)
+                {
+                    bool seen = 
+                        StackTraceHelper.DoesStackTraceContainMethod("ApplyDeletesAndUpdates") ||
+                        StackTraceHelper.DoesStackTraceContainMethod("SlowFileExists");                 
+
+                    if (!seen)
+                    {
+                        // Only fail once we are no longer in applyDeletes
+                        failed = true;
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TEST: mock failure: now fail");
+                            Console.WriteLine(Environment.StackTrace);
+                        }
+                        throw new IOException("fail after applyDeletes");
+                    }
+                }
+                if (!failed)
+                {
+                    if (StackTraceHelper.DoesStackTraceContainMethod("ApplyDeletesAndUpdates"))
+                    {
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TEST: mock failure: saw applyDeletes");
+                            Console.WriteLine(Environment.StackTrace);
+                        }
+                        sawMaybe = true;
+                    }              
+                }
+            }
+        }
+
+        // this test tests that the files created by the docs writer before
+        // a segment is written are cleaned up if there's an i/o error
+        [Test]
+        public virtual void TestErrorInDocsWriterAdd()
+        {
+            MockDirectoryWrapper.Failure failure = new FailureAnonymousInnerClassHelper2(this);
+
+            // create a couple of files
+
+            string[] keywords = new string[] { "1", "2" };
+            string[] unindexed = new string[] { "Netherlands", "Italy" };
+            string[] unstored = new string[] { "Amsterdam has lots of bridges", "Venice has lots of canals" };
+            string[] text = new string[] { "Amsterdam", "Venice" };
+
+            MockDirectoryWrapper dir = NewMockDirectory();
+            IndexWriter modifier = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)));
+            modifier.Commit();
+            dir.FailOn(failure.Reset());
+
+            FieldType custom1 = new FieldType();
+            custom1.IsStored = true;
+            for (int i = 0; i < keywords.Length; i++)
+            {
+                Document doc = new Document();
+                doc.Add(NewStringField("id", keywords[i], Field.Store.YES));
+                doc.Add(NewField("country", unindexed[i], custom1));
+                doc.Add(NewTextField("contents", unstored[i], Field.Store.NO));
+                doc.Add(NewTextField("city", text[i], Field.Store.YES));
+                try
+                {
+                    modifier.AddDocument(doc);
+                }
+                catch (IOException io)
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST: got expected exc:");
+                        Console.WriteLine(io.StackTrace);
+                    }
+                    break;
+                }
+            }
+
+            modifier.Dispose();
+            TestIndexWriter.AssertNoUnreferencedFiles(dir, "docsWriter.abort() failed to delete unreferenced files");
+            dir.Dispose();
+        }
+
+        private class FailureAnonymousInnerClassHelper2 : MockDirectoryWrapper.Failure
+        {
+            private readonly TestIndexWriterDelete OuterInstance;
+
+            public FailureAnonymousInnerClassHelper2(TestIndexWriterDelete outerInstance)
+            {
+                this.OuterInstance = outerInstance;
+                failed = false;
+            }
+
+            internal bool failed;
+
+            public override MockDirectoryWrapper.Failure Reset()
+            {
+                failed = false;
+                return this;
+            }
+
+            public override void Eval(MockDirectoryWrapper dir)
+            {
+                if (!failed)
+                {
+                    failed = true;
+                    throw new IOException("fail in add doc");
+                }
+            }
+        }
+
+        [Test]
+        public virtual void TestDeleteNullQuery()
+        {
+            Directory dir = NewDirectory();
+            IndexWriter modifier = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.WHITESPACE, false)));
+
+            for (int i = 0; i < 5; i++)
+            {
+                AddDoc(modifier, i, 2 * i);
+            }
+
+            modifier.DeleteDocuments(new TermQuery(new Term("nada", "nada")));
+            modifier.Commit();
+            Assert.AreEqual(5, modifier.NumDocs);
+            modifier.Dispose();
+            dir.Dispose();
+        }
+
+        [Test]
+        public virtual void TestDeleteAllSlowly()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), dir, Similarity, TimeZone);
+            int NUM_DOCS = AtLeast(1000);
+            IList<int?> ids = new List<int?>(NUM_DOCS);
+            for (int id = 0; id < NUM_DOCS; id++)
+            {
+                ids.Add(id);
+            }
+            Collections.Shuffle(ids);
+            foreach (int id in ids)
+            {
+                Document doc = new Document();
+                doc.Add(NewStringField("id", "" + id, Field.Store.NO));
+                w.AddDocument(doc);
+            }
+            Collections.Shuffle(ids);
+            int upto = 0;
+            while (upto < ids.Count)
+            {
+                int left = ids.Count - upto;
+                int inc = Math.Min(left, TestUtil.NextInt(Random(), 1, 20));
+                int limit = upto + inc;
+                while (upto < limit)
+                {
+                    w.DeleteDocuments(new Term("id", "" + ids[upto++]));
+                }
+                IndexReader r = w.Reader;
+                Assert.AreEqual(NUM_DOCS - upto, r.NumDocs);
+                r.Dispose();
+            }
+
+            w.Dispose();
+            dir.Dispose();
+        }
+
+        [Test]
+        public virtual void TestIndexingThenDeleting()
+        {
+            // TODO: move this test to its own class and just @SuppressCodecs?
+            // TODO: is it enough to just use newFSDirectory?
+            string fieldFormat = TestUtil.GetPostingsFormat("field");
+            AssumeFalse("this test cannot run with Memory codec", fieldFormat.Equals("Memory"));
+            AssumeFalse("this test cannot run with SimpleText codec", fieldFormat.Equals("SimpleText"));
+            AssumeFalse("this test cannot run with Direct codec", fieldFormat.Equals("Direct"));
+            Random r = Random();
+            Directory dir = NewDirectory();
+            // note this test explicitly disables payloads
+            Analyzer analyzer = new AnalyzerAnonymousInnerClassHelper(this);
+            IndexWriter w = new IndexWriter(dir, (IndexWriterConfig)NewIndexWriterConfig(TEST_VERSION_CURRENT, analyzer).SetRAMBufferSizeMB(1.0).SetMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH).SetMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH));
+            Document doc = new Document();
+            doc.Add(NewTextField("field", "go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20", Field.Store.NO));
+            int num = AtLeast(3);
+            for (int iter = 0; iter < num; iter++)
+            {
+                int count = 0;
+
+                bool doIndexing = r.NextBoolean();
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: iter doIndexing=" + doIndexing);
+                }
+                if (doIndexing)
+                {
+                    // Add docs until a flush is triggered
+                    int startFlushCount = w.FlushCount;
+                    while (w.FlushCount == startFlushCount)
+                    {
+                        w.AddDocument(doc);
+                        count++;
+                    }
+                }
+                else
+                {
+                    // Delete docs until a flush is triggered
+                    int startFlushCount = w.FlushCount;
+                    while (w.FlushCount == startFlushCount)
+                    {
+                        w.DeleteDocuments(new Term("foo", "" + count));
+                        count++;
+                    }
+                }
+                Assert.IsTrue(count > 2500, "flush happened too quickly during " + (doIndexing ? "indexing" : "deleting") + " count=" + count);
+            }
+            w.Dispose();
+            dir.Dispose();
+        }
+
+        private class AnalyzerAnonymousInnerClassHelper : Analyzer
+        {
+            private readonly TestIndexWriterDelete OuterInstance;
+
+            public AnalyzerAnonymousInnerClassHelper(TestIndexWriterDelete outerInstance)
+            {
+                this.OuterInstance = outerInstance;
+            }
+
+            protected internal override TokenStreamComponents CreateComponents(string fieldName, TextReader reader)
+            {
+                return new TokenStreamComponents(new MockTokenizer(reader, MockTokenizer.WHITESPACE, true));
+            }
+        }
+
+        // LUCENE-3340: make sure deletes that we don't apply
+        // during flush (ie are just pushed into the stream) are
+        // in fact later flushed due to their RAM usage:
+        [Test]
+        public virtual void TestFlushPushedDeletesByRAM()
+        {
+            Directory dir = NewDirectory();
+            // Cannot use RandomIndexWriter because we don't want to
+            // ever call commit() for this test:
+            // note: tiny rambuffer used, as with a 1MB buffer the test is too slow (flush @ 128,999)
+            IndexWriter w = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetRAMBufferSizeMB(0.1f).SetMaxBufferedDocs(1000).SetMergePolicy(NoMergePolicy.NO_COMPOUND_FILES).SetReaderPooling(false));
+            int count = 0;
+            while (true)
+            {
+                Document doc = new Document();
+                doc.Add(new StringField("id", count + "", Field.Store.NO));
+                Term delTerm;
+                if (count == 1010)
+                {
+                    // this is the only delete that applies
+                    delTerm = new Term("id", "" + 0);
+                }
+                else
+                {
+                    // These get buffered, taking up RAM, but delete
+                    // nothing when applied:
+                    delTerm = new Term("id", "x" + count);
+                }
+                w.UpdateDocument(delTerm, doc);
+                // Eventually segment 0 should get a del docs:
+                // TODO: fix this test
+                if (SlowFileExists(dir, "_0_1.del") || SlowFileExists(dir, "_0_1.liv"))
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST: deletes created @ count=" + count);
+                    }
+                    break;
+                }
+                count++;
+
+                // Today we applyDeletes @ count=21553; even if we make
+                // sizable improvements to RAM efficiency of buffered
+                // del term we're unlikely to go over 100K:
+                if (count > 100000)
+                {
+                    Assert.Fail("delete's were not applied");
+                }
+            }
+            w.Dispose();
+            dir.Dispose();
+        }
+
+        // LUCENE-3340: make sure deletes that we don't apply
+        // during flush (ie are just pushed into the stream) are
+        // in fact later flushed due to their RAM usage:
+        [Test]
+        public virtual void TestFlushPushedDeletesByCount()
+        {
+            Directory dir = NewDirectory();
+            // Cannot use RandomIndexWriter because we don't want to
+            // ever call commit() for this test:
+            int flushAtDelCount = AtLeast(1020);
+            IndexWriter w = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetMaxBufferedDeleteTerms(flushAtDelCount).SetMaxBufferedDocs(1000).SetRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH).SetMergePolicy(NoMergePolicy.NO_COMPOUND_FILES).SetReaderPooling(false));
+            int count = 0;
+            while (true)
+            {
+                Document doc = new Document();
+                doc.Add(new StringField("id", count + "", Field.Store.NO));
+                Term delTerm;
+                if (count == 1010)
+                {
+                    // this is the only delete that applies
+                    delTerm = new Term("id", "" + 0);
+                }
+                else
+                {
+                    // These get buffered, taking up RAM, but delete
+                    // nothing when applied:
+                    delTerm = new Term("id", "x" + count);
+                }
+                w.UpdateDocument(delTerm, doc);
+                // Eventually segment 0 should get a del docs:
+                // TODO: fix this test
+                if (SlowFileExists(dir, "_0_1.del") || SlowFileExists(dir, "_0_1.liv"))
+                {
+                    break;
+                }
+                count++;
+                if (count > flushAtDelCount)
+                {
+                    Assert.Fail("delete's were not applied at count=" + flushAtDelCount);
+                }
+            }
+            w.Dispose();
+            dir.Dispose();
+        }
+
+        // Make sure buffered (pushed) deletes don't use up so
+        // much RAM that it forces long tail of tiny segments:
+#if !NETSTANDARD
+        // LUCENENET: There is no Timeout on NUnit for .NET Core.
+        [Timeout(int.MaxValue)]
+#endif
+        [Test, LongRunningTest, HasTimeout]
+        public virtual void TestApplyDeletesOnFlush()
+        {
+            Directory dir = NewDirectory();
+            // Cannot use RandomIndexWriter because we don't want to
+            // ever call commit() for this test:
+            AtomicInt32 docsInSegment = new AtomicInt32();
+            AtomicBoolean closing = new AtomicBoolean();
+            AtomicBoolean sawAfterFlush = new AtomicBoolean();
+            IndexWriter w = new IndexWriterAnonymousInnerClassHelper(this, dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetRAMBufferSizeMB(0.5).SetMaxBufferedDocs(-1).SetMergePolicy(NoMergePolicy.NO_COMPOUND_FILES).SetReaderPooling(false), docsInSegment, closing, sawAfterFlush);
+            int id = 0;
+            while (true)
+            {
+                StringBuilder sb = new StringBuilder();
+                for (int termIDX = 0; termIDX < 100; termIDX++)
+                {
+                    sb.Append(' ').Append(TestUtil.RandomRealisticUnicodeString(Random()));
+                }
+                if (id == 500)
+                {
+                    w.DeleteDocuments(new Term("id", "0"));
+                }
+                Document doc = new Document();
+                doc.Add(NewStringField("id", "" + id, Field.Store.NO));
+                doc.Add(NewTextField("body", sb.ToString(), Field.Store.NO));
+                w.UpdateDocument(new Term("id", "" + id), doc);
+                docsInSegment.IncrementAndGet();
+                // TODO: fix this test
+                if (SlowFileExists(dir, "_0_1.del") || SlowFileExists(dir, "_0_1.liv"))
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST: deletes created @ id=" + id);
+                    }
+                    break;
+                }
+                id++;
+            }
+            closing.Set(true);
+            Assert.IsTrue(sawAfterFlush.Get());
+            w.Dispose();
+            dir.Dispose();
+        }
+
+        private class IndexWriterAnonymousInnerClassHelper : IndexWriter
+        {
+            private readonly TestIndexWriterDelete OuterInstance;
+
+            private AtomicInt32 DocsInSegment;
+            private AtomicBoolean Closing;
+            private AtomicBoolean SawAfterFlush;
+
+            public IndexWriterAnonymousInnerClassHelper(TestIndexWriterDelete outerInstance, Directory dir, IndexWriterConfig setReaderPooling, AtomicInt32 docsInSegment, AtomicBoolean closing, AtomicBoolean sawAfterFlush)
+                : base(dir, setReaderPooling)
+            {
+                this.OuterInstance = outerInstance;
+                this.DocsInSegment = docsInSegment;
+                this.Closing = closing;
+                this.SawAfterFlush = sawAfterFlush;
+            }
+
+            protected override void DoAfterFlush()
+            {
+                Assert.IsTrue(Closing.Get() || DocsInSegment.Get() >= 7, "only " + DocsInSegment.Get() + " in segment");
+                DocsInSegment.Set(0);
+                SawAfterFlush.Set(true);
+            }
+        }
+
+        // LUCENE-4455
+        [Test]
+        public virtual void TestDeletesCheckIndexOutput()
+        {
+            Directory dir = NewDirectory();
+            IndexWriterConfig iwc = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()));
+            iwc.SetMaxBufferedDocs(2);
+            IndexWriter w = new IndexWriter(dir, (IndexWriterConfig)iwc.Clone());
+            Document doc = new Document();
+            doc.Add(NewField("field", "0", StringField.TYPE_NOT_STORED));
+            w.AddDocument(doc);
+
+            doc = new Document();
+            doc.Add(NewField("field", "1", StringField.TYPE_NOT_STORED));
+            w.AddDocument(doc);
+            w.Commit();
+            Assert.AreEqual(1, w.SegmentCount);
+
+            w.DeleteDocuments(new Term("field", "0"));
+            w.Commit();
+            Assert.AreEqual(1, w.SegmentCount);
+            w.Dispose();
+
+            ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
+            //MemoryStream bos = new MemoryStream(1024);
+            CheckIndex checker = new CheckIndex(dir);
+            checker.InfoStream = new StreamWriter(bos, Encoding.UTF8);
+            CheckIndex.Status indexStatus = checker.DoCheckIndex(null);
+            Assert.IsTrue(indexStatus.Clean);
+            checker.FlushInfoStream();
+            string s = bos.ToString();
+
+            // Segment should have deletions:
+            Assert.IsTrue(s.Contains("has deletions"), "string was: " + s);
+            w = new IndexWriter(dir, (IndexWriterConfig)iwc.Clone());
+            w.ForceMerge(1);
+            w.Dispose();
+
+            bos = new ByteArrayOutputStream(1024);
+            checker.InfoStream = new StreamWriter(bos, Encoding.UTF8);
+            indexStatus = checker.DoCheckIndex(null);
+            Assert.IsTrue(indexStatus.Clean);
+            checker.FlushInfoStream();
+            s = bos.ToString();
+            Assert.IsFalse(s.Contains("has deletions"));
+            dir.Dispose();
+        }
+
+        [Test]
+        public virtual void TestTryDeleteDocument()
+        {
+            Directory d = NewDirectory();
+
+            IndexWriterConfig iwc = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()));
+            IndexWriter w = new IndexWriter(d, iwc);
+            Document doc = new Document();
+            w.AddDocument(doc);
+            w.AddDocument(doc);
+            w.AddDocument(doc);
+            w.Dispose();
+
+            iwc = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()));
+            iwc.SetOpenMode(OpenMode.APPEND);
+            w = new IndexWriter(d, iwc);
+            IndexReader r = DirectoryReader.Open(w, false);
+            Assert.IsTrue(w.TryDeleteDocument(r, 1));
+            Assert.IsTrue(w.TryDeleteDocument(r.Leaves[0].Reader, 0));
+            r.Dispose();
+            w.Dispose();
+
+            r = DirectoryReader.Open(d);
+            Assert.AreEqual(2, r.NumDeletedDocs);
+            Assert.IsNotNull(MultiFields.GetLiveDocs(r));
+            r.Dispose();
+            d.Dispose();
+        }
+    }
+}
\ No newline at end of file


Mime
View raw message