blob: bc0cbd4569faecc8df4cc81973c7336dc8ce10c0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using Lucene.Net.Support;
using NUnit.Framework;
using WhitespaceAnalyzer = Lucene.Net.Analysis.WhitespaceAnalyzer;
using Document = Lucene.Net.Documents.Document;
using Field = Lucene.Net.Documents.Field;
using Directory = Lucene.Net.Store.Directory;
using MockRAMDirectory = Lucene.Net.Store.MockRAMDirectory;
using IndexSearcher = Lucene.Net.Search.IndexSearcher;
using ScoreDoc = Lucene.Net.Search.ScoreDoc;
using TermQuery = Lucene.Net.Search.TermQuery;
using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
namespace Lucene.Net.Index
{
[TestFixture]
public class TestIndexWriterDelete:LuceneTestCase
{
private class AnonymousClassFailure:MockRAMDirectory.Failure
{
public AnonymousClassFailure(TestIndexWriterDelete enclosingInstance)
{
InitBlock(enclosingInstance);
}
private void InitBlock(TestIndexWriterDelete enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private TestIndexWriterDelete enclosingInstance;
public TestIndexWriterDelete Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
internal bool sawMaybe = false;
internal bool failed = false;
public override MockRAMDirectory.Failure Reset()
{
sawMaybe = false;
failed = false;
return this;
}
public override void Eval(MockRAMDirectory dir)
{
if (sawMaybe && !failed)
{
bool seen = false;
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
for (int i = 0; i < trace.FrameCount; i++)
{
System.Diagnostics.StackFrame sf = trace.GetFrame(i);
if ("ApplyDeletes".Equals(sf.GetMethod().Name))
{
seen = true;
break;
}
}
if (!seen)
{
// Only fail once we are no longer in applyDeletes
failed = true;
throw new System.IO.IOException("fail after applyDeletes");
}
}
if (!failed)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
for (int i = 0; i < trace.FrameCount; i++)
{
System.Diagnostics.StackFrame sf = trace.GetFrame(i);
if ("ApplyDeletes".Equals(sf.GetMethod().Name))
{
sawMaybe = true;
break;
}
}
}
}
}
private class AnonymousClassFailure1:MockRAMDirectory.Failure
{
public AnonymousClassFailure1(TestIndexWriterDelete enclosingInstance)
{
InitBlock(enclosingInstance);
}
private void InitBlock(TestIndexWriterDelete enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private TestIndexWriterDelete enclosingInstance;
public TestIndexWriterDelete Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
internal bool failed = false;
public override MockRAMDirectory.Failure Reset()
{
failed = false;
return this;
}
public override void Eval(MockRAMDirectory dir)
{
if (!failed)
{
failed = true;
throw new System.IO.IOException("fail in add doc");
}
}
}
// test the simple case
[Test]
public virtual void TestSimpleCase()
{
System.String[] keywords = new System.String[] {"1", "2"};
System.String[] unindexed = new System.String[] {"Netherlands", "Italy"};
System.String[] unstored = new System.String[]
{"Amsterdam has lots of bridges", "Venice has lots of canals"};
System.String[] text = new System.String[] {"Amsterdam", "Venice"};
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.UseCompoundFile = true;
modifier.SetMaxBufferedDeleteTerms(1);
for (int i = 0; i < keywords.Length; i++)
{
Document doc = new Document();
doc.Add(new Field("id", keywords[i], Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("country", unindexed[i], Field.Store.YES, Field.Index.NO));
doc.Add(new Field("contents", unstored[i], Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("city", text[i], Field.Store.YES, Field.Index.ANALYZED));
modifier.AddDocument(doc);
}
modifier.Optimize();
modifier.Commit();
Term term = new Term("city", "Amsterdam");
int hitCount = GetHitCount(dir, term);
Assert.AreEqual(1, hitCount);
modifier.DeleteDocuments(term);
modifier.Commit();
hitCount = GetHitCount(dir, term);
Assert.AreEqual(0, hitCount);
modifier.Close();
dir.Close();
}
// test when delete terms only apply to disk segments
[Test]
public virtual void TestNonRAMDelete()
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true,
IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(2);
modifier.SetMaxBufferedDeleteTerms(2);
int id = 0;
int value_Renamed = 100;
for (int i = 0; i < 7; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.Commit();
Assert.AreEqual(0, modifier.GetNumBufferedDocuments());
Assert.IsTrue(0 < modifier.GetSegmentCount());
modifier.Commit();
IndexReader reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
modifier.DeleteDocuments(new Term("value", System.Convert.ToString(value_Renamed)));
modifier.Commit();
reader = IndexReader.Open(dir, true);
Assert.AreEqual(0, reader.NumDocs());
reader.Close();
modifier.Close();
dir.Close();
}
[Test]
public virtual void TestMaxBufferedDeletes()
{
Directory dir = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true,
IndexWriter.MaxFieldLength.UNLIMITED);
writer.SetMaxBufferedDeleteTerms(1);
writer.DeleteDocuments(new Term("foobar", "1"));
writer.DeleteDocuments(new Term("foobar", "1"));
writer.DeleteDocuments(new Term("foobar", "1"));
Assert.AreEqual(3, writer.GetFlushDeletesCount());
writer.Close();
dir.Close();
}
// test when delete terms only apply to ram segments
[Test]
public virtual void TestRAMDeletes()
{
for (int t = 0; t < 2; t++)
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(4);
modifier.SetMaxBufferedDeleteTerms(4);
int id = 0;
int value_Renamed = 100;
AddDoc(modifier, ++id, value_Renamed);
if (0 == t)
modifier.DeleteDocuments(new Term("value", System.Convert.ToString(value_Renamed)));
else
modifier.DeleteDocuments(new TermQuery(new Term("value", System.Convert.ToString(value_Renamed))));
AddDoc(modifier, ++id, value_Renamed);
if (0 == t)
{
modifier.DeleteDocuments(new Term("value", System.Convert.ToString(value_Renamed)));
Assert.AreEqual(2, modifier.GetNumBufferedDeleteTerms());
Assert.AreEqual(1, modifier.GetBufferedDeleteTermsSize());
}
else
modifier.DeleteDocuments(new TermQuery(new Term("value", System.Convert.ToString(value_Renamed))));
AddDoc(modifier, ++id, value_Renamed);
Assert.AreEqual(0, modifier.GetSegmentCount());
modifier.Commit();
modifier.Commit();
IndexReader reader = IndexReader.Open(dir, true);
Assert.AreEqual(1, reader.NumDocs());
int hitCount = GetHitCount(dir, new Term("id", System.Convert.ToString(id)));
Assert.AreEqual(1, hitCount);
reader.Close();
modifier.Close();
dir.Close();
}
}
// test when delete terms apply to both disk and ram segments
[Test]
public virtual void TestBothDeletes()
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(100);
modifier.SetMaxBufferedDeleteTerms(100);
int id = 0;
int value_Renamed = 100;
for (int i = 0; i < 5; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
value_Renamed = 200;
for (int i = 0; i < 5; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.Commit();
for (int i = 0; i < 5; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.DeleteDocuments(new Term("value", System.Convert.ToString(value_Renamed)));
modifier.Commit();
IndexReader reader = IndexReader.Open(dir, true);
Assert.AreEqual(5, reader.NumDocs());
modifier.Close();
}
// test that batched delete terms are flushed together
[Test]
public virtual void TestBatchDeletes()
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true,
IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(2);
modifier.SetMaxBufferedDeleteTerms(2);
int id = 0;
int value_Renamed = 100;
for (int i = 0; i < 7; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.Commit();
IndexReader reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
id = 0;
modifier.DeleteDocuments(new Term("id", System.Convert.ToString(++id)));
modifier.DeleteDocuments(new Term("id", System.Convert.ToString(++id)));
modifier.Commit();
reader = IndexReader.Open(dir, true);
Assert.AreEqual(5, reader.NumDocs());
reader.Close();
Term[] terms = new Term[3];
for (int i = 0; i < terms.Length; i++)
{
terms[i] = new Term("id", System.Convert.ToString(++id));
}
modifier.DeleteDocuments(terms);
modifier.Commit();
reader = IndexReader.Open(dir, true);
Assert.AreEqual(2, reader.NumDocs());
reader.Close();
modifier.Close();
dir.Close();
}
// test deleteAll()
[Test]
public virtual void TestDeleteAll()
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(2);
modifier.SetMaxBufferedDeleteTerms(2);
int id = 0;
int value_Renamed = 100;
for (int i = 0; i < 7; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.Commit();
IndexReader reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
// Add 1 doc (so we will have something buffered)
AddDoc(modifier, 99, value_Renamed);
// Delete all
modifier.DeleteAll();
// Delete all shouldn't be on disk yet
reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
// Add a doc and update a doc (after the deleteAll, before the commit)
AddDoc(modifier, 101, value_Renamed);
UpdateDoc(modifier, 102, value_Renamed);
// commit the delete all
modifier.Commit();
// Validate there are no docs left
reader = IndexReader.Open(dir, true);
Assert.AreEqual(2, reader.NumDocs());
reader.Close();
modifier.Close();
dir.Close();
}
// test rollback of deleteAll()
[Test]
public virtual void TestDeleteAllRollback()
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(2);
modifier.SetMaxBufferedDeleteTerms(2);
int id = 0;
int value_Renamed = 100;
for (int i = 0; i < 7; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.Commit();
AddDoc(modifier, ++id, value_Renamed);
IndexReader reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
// Delete all
modifier.DeleteAll();
// Roll it back
modifier.Rollback();
modifier.Close();
// Validate that the docs are still there
reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
dir.Close();
}
// test deleteAll() w/ near real-time reader
[Test]
public virtual void TestDeleteAllNRT()
{
Directory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(2);
modifier.SetMaxBufferedDeleteTerms(2);
int id = 0;
int value_Renamed = 100;
for (int i = 0; i < 7; i++)
{
AddDoc(modifier, ++id, value_Renamed);
}
modifier.Commit();
IndexReader reader = modifier.GetReader();
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
AddDoc(modifier, ++id, value_Renamed);
AddDoc(modifier, ++id, value_Renamed);
// Delete all
modifier.DeleteAll();
reader = modifier.GetReader();
Assert.AreEqual(0, reader.NumDocs());
reader.Close();
// Roll it back
modifier.Rollback();
modifier.Close();
// Validate that the docs are still there
reader = IndexReader.Open(dir, true);
Assert.AreEqual(7, reader.NumDocs());
reader.Close();
dir.Close();
}
private void UpdateDoc(IndexWriter modifier, int id, int value_Renamed)
{
Document doc = new Document();
doc.Add(new Field("content", "aaa", Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("id", System.Convert.ToString(id), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("value", System.Convert.ToString(value_Renamed), Field.Store.NO, Field.Index.NOT_ANALYZED));
modifier.UpdateDocument(new Term("id", System.Convert.ToString(id)), doc);
}
private void AddDoc(IndexWriter modifier, int id, int value_Renamed)
{
Document doc = new Document();
doc.Add(new Field("content", "aaa", Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("id", System.Convert.ToString(id), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("value", System.Convert.ToString(value_Renamed), Field.Store.NO, Field.Index.NOT_ANALYZED));
modifier.AddDocument(doc);
}
private int GetHitCount(Directory dir, Term term)
{
IndexSearcher searcher = new IndexSearcher(dir, true);
int hitCount = searcher.Search(new TermQuery(term), null, 1000).TotalHits;
searcher.Close();
return hitCount;
}
[Test]
public virtual void TestDeletesOnDiskFull()
{
TestOperationsOnDiskFull(false);
}
[Test]
public virtual void TestUpdatesOnDiskFull()
{
TestOperationsOnDiskFull(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 TestOperationsOnDiskFull(bool updates)
{
bool debug = false;
Term searchTerm = new Term("content", "aaa");
int START_COUNT = 157;
int END_COUNT = 144;
// First build up a starting index:
MockRAMDirectory startDir = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(startDir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
for (int i = 0; i < 157; i++)
{
Document d = new Document();
d.Add(new Field("id", System.Convert.ToString(i), Field.Store.YES, Field.Index.NOT_ANALYZED));
d.Add(new Field("content", "aaa " + i, Field.Store.NO, Field.Index.ANALYZED));
writer.AddDocument(d);
}
writer.Close();
long diskUsage = startDir.SizeInBytes();
long diskFree = diskUsage + 10;
System.IO.IOException err = null;
bool done = false;
// Iterate w/ ever increasing free disk space:
while (!done)
{
MockRAMDirectory dir = new MockRAMDirectory(startDir);
dir.SetPreventDoubleWrite(false);
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
modifier.SetMaxBufferedDocs(1000); // use flush or close
modifier.SetMaxBufferedDeleteTerms(1000); // use flush or close
// 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++)
{
double rate = 0.1;
double diskRatio = ((double) diskFree)/diskUsage;
long thisDiskFree;
System.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 (debug)
{
System.Console.Out.WriteLine("\ncycle: " + diskFree + " bytes");
}
testName = "disk full during reader.close() @ " + thisDiskFree + " bytes";
}
else
{
thisDiskFree = 0;
rate = 0.0;
if (debug)
{
System.Console.Out.WriteLine("\ncycle: same writer: unlimited disk space");
}
testName = "reader re-use after disk full";
}
dir.SetMaxSizeInBytes(thisDiskFree);
dir.SetRandomIOExceptionRate(rate, diskFree);
try
{
if (0 == x)
{
int docId = 12;
for (int i = 0; i < 13; i++)
{
if (updates)
{
Document d = new Document();
d.Add(new Field("id", System.Convert.ToString(i), Field.Store.YES,
Field.Index.NOT_ANALYZED));
d.Add(new Field("content", "bbb " + i, Field.Store.NO, Field.Index.ANALYZED));
modifier.UpdateDocument(new Term("id", System.Convert.ToString(docId)), d);
}
else
{
// deletes
modifier.DeleteDocuments(new Term("id", System.Convert.ToString(docId)));
// modifier.setNorm(docId, "contents", (float)2.0);
}
docId += 12;
}
}
modifier.Close();
success = true;
if (0 == x)
{
done = true;
}
}
catch (System.IO.IOException e)
{
if (debug)
{
System.Console.Out.WriteLine(" hit IOException: " + e);
System.Console.Out.WriteLine(e.StackTrace);
}
err = e;
if (1 == x)
{
System.Console.Error.WriteLine(e.StackTrace);
Assert.Fail(testName + " hit IOException after disk space was freed up");
}
}
// If the close() succeeded, make sure there are
// no unreferenced files.
if (success)
{
Lucene.Net.Util._TestUtil.CheckIndex(dir);
TestIndexWriter.AssertNoUnreferencedFiles(dir, "after writer.close");
}
// 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 = IndexReader.Open(dir, true);
}
catch (System.IO.IOException e)
{
System.Console.Error.WriteLine(e.StackTrace);
Assert.Fail(testName + ":exception when creating IndexReader after disk full during close: " + e);
}
IndexSearcher searcher = new IndexSearcher(newReader);
ScoreDoc[] hits = null;
try
{
hits = searcher.Search(new TermQuery(searchTerm), null, 1000).ScoreDocs;
}
catch (System.IO.IOException e)
{
System.Console.Error.WriteLine(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)
{
System.Console.Error.WriteLine(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);
}
}
searcher.Close();
newReader.Close();
if (result2 == END_COUNT)
{
break;
}
}
dir.Close();
// Try again with 10 more bytes of free space:
diskFree += 10;
}
}
// This test tests that buffered deletes are cleared when
// an Exception is hit during flush.
[Test]
public virtual void TestErrorAfterApplyDeletes()
{
MockRAMDirectory.Failure failure = new AnonymousClassFailure(this);
// create a couple of files
System.String[] keywords = new System.String[] {"1", "2"};
System.String[] unindexed = new System.String[] {"Netherlands", "Italy"};
System.String[] unstored = new System.String[]
{"Amsterdam has lots of bridges", "Venice has lots of canals"};
System.String[] text = new System.String[] {"Amsterdam", "Venice"};
MockRAMDirectory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
modifier.UseCompoundFile = true;
modifier.SetMaxBufferedDeleteTerms(2);
dir.FailOn(failure.Reset());
for (int i = 0; i < keywords.Length; i++)
{
Document doc = new Document();
doc.Add(new Field("id", keywords[i], Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("country", unindexed[i], Field.Store.YES, Field.Index.NO));
doc.Add(new Field("contents", unstored[i], Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("city", text[i], Field.Store.YES, Field.Index.ANALYZED));
modifier.AddDocument(doc);
}
// flush (and commit if ac)
modifier.Optimize();
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
modifier.DeleteDocuments(term);
// add a doc (needed for the !ac case; see below)
// doc remains buffered
Document doc2 = new Document();
modifier.AddDocument(doc2);
// 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
// in the !ac case, 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
{
modifier.Commit();
}
catch (System.IO.IOException ioe)
{
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.Close();
dir.Close();
}
// 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()
{
MockRAMDirectory.Failure failure = new AnonymousClassFailure1(this);
// create a couple of files
System.String[] keywords = new System.String[] {"1", "2"};
System.String[] unindexed = new System.String[] {"Netherlands", "Italy"};
System.String[] unstored = new System.String[]
{"Amsterdam has lots of bridges", "Venice has lots of canals"};
System.String[] text = new System.String[] {"Amsterdam", "Venice"};
MockRAMDirectory dir = new MockRAMDirectory();
IndexWriter modifier = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
dir.FailOn(failure.Reset());
for (int i = 0; i < keywords.Length; i++)
{
Document doc = new Document();
doc.Add(new Field("id", keywords[i], Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("country", unindexed[i], Field.Store.YES, Field.Index.NO));
doc.Add(new Field("contents", unstored[i], Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("city", text[i], Field.Store.YES, Field.Index.ANALYZED));
try
{
modifier.AddDocument(doc);
}
catch (System.IO.IOException io)
{
break;
}
}
System.String[] startFiles = dir.ListAll();
SegmentInfos infos = new SegmentInfos();
infos.Read(dir);
new IndexFileDeleter(dir, new KeepOnlyLastCommitDeletionPolicy(), infos, null, null, null);
System.String[] endFiles = dir.ListAll();
Assert.IsTrue(CollectionsHelper.CompareStringArrays(startFiles, endFiles),
"docswriter abort() failed to delete unreferenced files:\n before delete:\n " +
ArrayToString(startFiles) + "\n after delete:\n " + ArrayToString(endFiles));
modifier.Close();
}
private System.String ArrayToString(System.String[] l)
{
System.String s = "";
for (int i = 0; i < l.Length; i++)
{
if (i > 0)
{
s += "\n ";
}
s += l[i];
}
return s;
}
}
}