blob: d50ad1603b266b7bad77373b10221548a5936292 [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 IndexReader = Lucene.Net.Index.IndexReader;
using IndexWriter = Lucene.Net.Index.IndexWriter;
using Term = Lucene.Net.Index.Term;
using NIOFSIndexInput = Lucene.Net.Store.NIOFSDirectory.NIOFSIndexInput;
using SimpleFSIndexInput = Lucene.Net.Store.SimpleFSDirectory.SimpleFSIndexInput;
using ArrayUtil = Lucene.Net.Util.ArrayUtil;
using IndexSearcher = Lucene.Net.Search.IndexSearcher;
using ScoreDoc = Lucene.Net.Search.ScoreDoc;
using TermQuery = Lucene.Net.Search.TermQuery;
using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
using _TestUtil = Lucene.Net.Util._TestUtil;
namespace Lucene.Net.Store
{
[TestFixture]
public class TestBufferedIndexInput:LuceneTestCase
{
private static void WriteBytes(System.IO.FileInfo aFile, long size)
{
System.IO.Stream stream = null;
try
{
stream = new System.IO.FileStream(aFile.FullName, System.IO.FileMode.Create);
for (int i = 0; i < size; i++)
{
stream.WriteByte((byte) Byten(i));
}
stream.Flush();
}
finally
{
if (stream != null)
{
stream.Close();
}
}
}
private const long TEST_FILE_LENGTH = 1024 * 1024;
// Call readByte() repeatedly, past the buffer boundary, and see that it
// is working as expected.
// Our input comes from a dynamically generated/ "file" - see
// MyBufferedIndexInput below.
[Test]
public virtual void TestReadByte()
{
MyBufferedIndexInput input = new MyBufferedIndexInput();
for (int i = 0; i < BufferedIndexInput.BUFFER_SIZE * 10; i++)
{
Assert.AreEqual(input.ReadByte(), Byten(i));
}
}
// Call readBytes() repeatedly, with various chunk sizes (from 1 byte to
// larger than the buffer size), and see that it returns the bytes we expect.
// Our input comes from a dynamically generated "file" -
// see MyBufferedIndexInput below.
[Test]
public virtual void TestReadBytes()
{
System.Random r = NewRandom();
MyBufferedIndexInput input = new MyBufferedIndexInput();
RunReadBytes(input, BufferedIndexInput.BUFFER_SIZE, r);
// This tests the workaround code for LUCENE-1566 where readBytesInternal
// provides a workaround for a JVM Bug that incorrectly raises a OOM Error
// when a large byte buffer is passed to a file read.
// NOTE: this does only test the chunked reads and NOT if the Bug is triggered.
//final int tmpFileSize = 1024 * 1024 * 5;
int inputBufferSize = 128;
System.String tempDirectory = System.IO.Path.GetTempPath();
System.IO.FileInfo tmpInputFile = new System.IO.FileInfo(System.IO.Path.Combine(tempDirectory, "IndexInput.tmpFile"));
System.IO.File.Delete(tmpInputFile.FullName);
WriteBytes(tmpInputFile, TEST_FILE_LENGTH);
// run test with chunk size of 10 bytes
RunReadBytesAndClose(new SimpleFSIndexInput(tmpInputFile, inputBufferSize, 10), inputBufferSize, r);
// run test with chunk size of 100 MB - default
RunReadBytesAndClose(new SimpleFSIndexInput(tmpInputFile, inputBufferSize, FSDirectory.DEFAULT_READ_CHUNK_SIZE), inputBufferSize, r);
Assert.Pass("Supressing Sub-Tests on NIOFSIndexInput classes");
// run test with chunk size of 10 bytes
//RunReadBytesAndClose(new NIOFSIndexInput(tmpInputFile, inputBufferSize, 10), inputBufferSize, r); // {{Aroush-2.9}} suppressing this test since NIOFSIndexInput isn't ported
System.Console.Out.WriteLine("Suppressing sub-test: 'RunReadBytesAndClose(new NIOFSIndexInput(tmpInputFile, inputBufferSize, 10), inputBufferSize, r);' since NIOFSIndexInput isn't ported");
// run test with chunk size of 100 MB - default
//RunReadBytesAndClose(new NIOFSIndexInput(tmpInputFile, inputBufferSize), inputBufferSize, r); // {{Aroush-2.9}} suppressing this test since NIOFSIndexInput isn't ported
System.Console.Out.WriteLine("Suppressing sub-test: 'RunReadBytesAndClose(new NIOFSIndexInput(tmpInputFile, inputBufferSize), inputBufferSize, r);' since NIOFSIndexInput isn't ported");
}
private void RunReadBytesAndClose(IndexInput input, int bufferSize, System.Random r)
{
try
{
RunReadBytes(input, bufferSize, r);
}
finally
{
input.Close();
}
}
private void RunReadBytes(IndexInput input, int bufferSize, System.Random r)
{
int pos = 0;
// gradually increasing size:
for (int size = 1; size < bufferSize * 10; size = size + size / 200 + 1)
{
CheckReadBytes(input, size, pos);
pos += size;
if (pos >= TEST_FILE_LENGTH)
{
// wrap
pos = 0;
input.Seek(0L);
}
}
// wildly fluctuating size:
for (long i = 0; i < 1000; i++)
{
int size = r.Next(10000);
CheckReadBytes(input, 1 + size, pos);
pos += 1 + size;
if (pos >= TEST_FILE_LENGTH)
{
// wrap
pos = 0;
input.Seek(0L);
}
}
// constant small size (7 bytes):
for (int i = 0; i < bufferSize; i++)
{
CheckReadBytes(input, 7, pos);
pos += 7;
if (pos >= TEST_FILE_LENGTH)
{
// wrap
pos = 0;
input.Seek(0L);
}
}
}
private byte[] buffer = new byte[10];
private void CheckReadBytes(IndexInput input, int size, int pos)
{
// Just to see that "offset" is treated properly in readBytes(), we
// add an arbitrary offset at the beginning of the array
int offset = size % 10; // arbitrary
buffer = ArrayUtil.Grow(buffer, offset + size);
Assert.AreEqual(pos, input.FilePointer);
long left = TEST_FILE_LENGTH - input.FilePointer;
if (left <= 0)
{
return ;
}
else if (left < size)
{
size = (int) left;
}
input.ReadBytes(buffer, offset, size);
Assert.AreEqual(pos + size, input.FilePointer);
for (int i = 0; i < size; i++)
{
Assert.AreEqual(Byten(pos + i), buffer[offset + i], "pos=" + i + " filepos=" + (pos + i));
}
}
// This tests that attempts to readBytes() past an EOF will fail, while
// reads up to the EOF will succeed. The EOF is determined by the
// BufferedIndexInput's arbitrary length() value.
[Test]
public virtual void TestEOF()
{
MyBufferedIndexInput input = new MyBufferedIndexInput(1024);
// see that we can read all the bytes at one go:
CheckReadBytes(input, (int) input.Length(), 0);
// go back and see that we can't read more than that, for small and
// large overflows:
int pos = (int) input.Length() - 10;
input.Seek(pos);
CheckReadBytes(input, 10, pos);
input.Seek(pos);
Assert.Throws<System.IO.IOException>(() => CheckReadBytes(input, 11, pos), "Block read past end of file");
input.Seek(pos);
Assert.Throws<System.IO.IOException>(() => CheckReadBytes(input, 50, pos), "Block read past end of file");
input.Seek(pos);
Assert.Throws<System.IO.IOException>(() => CheckReadBytes(input, 100000, pos), "Block read past end of file");
}
// byten emulates a file - byten(n) returns the n'th byte in that file.
// MyBufferedIndexInput reads this "file".
private static byte Byten(long n)
{
return (byte) (n * n % 256);
}
private class MyBufferedIndexInput:BufferedIndexInput
{
private long pos;
private long len;
public MyBufferedIndexInput(long len)
{
this.len = len;
this.pos = 0;
}
public MyBufferedIndexInput():this(System.Int64.MaxValue)
{
}
public override void ReadInternal(byte[] b, int offset, int length)
{
for (int i = offset; i < offset + length; i++)
b[i] = Lucene.Net.Store.TestBufferedIndexInput.Byten(pos++);
}
public override void SeekInternal(long pos)
{
this.pos = pos;
}
protected override void Dispose(bool disposing)
{
// Do nothing
}
public override long Length()
{
return len;
}
}
[Test]
public virtual void TestSetBufferSize()
{
System.IO.DirectoryInfo indexDir = new System.IO.DirectoryInfo(System.IO.Path.Combine(AppSettings.Get("tempDir", ""), "testSetBufferSize"));
MockFSDirectory dir = new MockFSDirectory(indexDir, NewRandom());
try
{
IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED);
writer.UseCompoundFile = false;
for (int i = 0; i < 37; i++)
{
Document doc = new Document();
doc.Add(new Field("content", "aaa bbb ccc ddd" + i, Field.Store.YES, Field.Index.ANALYZED));
doc.Add(new Field("id", "" + i, Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(doc);
}
writer.Close();
dir.allIndexInputs.Clear();
IndexReader reader = IndexReader.Open(dir, false);
Term aaa = new Term("content", "aaa");
Term bbb = new Term("content", "bbb");
Term ccc = new Term("content", "ccc");
Assert.AreEqual(37, reader.DocFreq(ccc));
reader.DeleteDocument(0);
Assert.AreEqual(37, reader.DocFreq(aaa));
dir.tweakBufferSizes();
reader.DeleteDocument(4);
Assert.AreEqual(reader.DocFreq(bbb), 37);
dir.tweakBufferSizes();
IndexSearcher searcher = new IndexSearcher(reader);
ScoreDoc[] hits = searcher.Search(new TermQuery(bbb), null, 1000).ScoreDocs;
dir.tweakBufferSizes();
Assert.AreEqual(35, hits.Length);
dir.tweakBufferSizes();
hits = searcher.Search(new TermQuery(new Term("id", "33")), null, 1000).ScoreDocs;
dir.tweakBufferSizes();
Assert.AreEqual(1, hits.Length);
hits = searcher.Search(new TermQuery(aaa), null, 1000).ScoreDocs;
dir.tweakBufferSizes();
Assert.AreEqual(35, hits.Length);
searcher.Close();
reader.Close();
}
finally
{
_TestUtil.RmDir(indexDir);
}
}
private class MockFSDirectory:Directory
{
internal System.Collections.IList allIndexInputs = new System.Collections.ArrayList();
internal System.Random rand;
private Directory dir;
private bool isDisposed;
public MockFSDirectory(System.IO.DirectoryInfo path, System.Random rand)
{
this.rand = rand;
interalLockFactory = new NoLockFactory();
dir = new SimpleFSDirectory(path, null);
}
public override IndexInput OpenInput(System.String name)
{
return OpenInput(name, BufferedIndexInput.BUFFER_SIZE);
}
public virtual void tweakBufferSizes()
{
System.Collections.IEnumerator it = allIndexInputs.GetEnumerator();
//int count = 0;
while (it.MoveNext())
{
BufferedIndexInput bii = (BufferedIndexInput) it.Current;
int bufferSize = 1024 + (int) System.Math.Abs(rand.Next() % 32768);
bii.SetBufferSize(bufferSize);
//count++;
}
//System.out.println("tweak'd " + count + " buffer sizes");
}
public override IndexInput OpenInput(System.String name, int bufferSize)
{
// Make random changes to buffer size
bufferSize = 1 + (int) System.Math.Abs(rand.Next() % 10);
IndexInput f = dir.OpenInput(name, bufferSize);
allIndexInputs.Add(f);
return f;
}
public override IndexOutput CreateOutput(System.String name)
{
return dir.CreateOutput(name);
}
protected override void Dispose(bool disposing)
{
if (isDisposed) return;
if (disposing)
{
if (dir != null)
{
dir.Close();
}
}
dir = null;
isDisposed = true;
}
public override void DeleteFile(System.String name)
{
dir.DeleteFile(name);
}
public override void TouchFile(System.String name)
{
dir.TouchFile(name);
}
public override long FileModified(System.String name)
{
return dir.FileModified(name);
}
public override bool FileExists(System.String name)
{
return dir.FileExists(name);
}
public override System.String[] ListAll()
{
return dir.ListAll();
}
public override long FileLength(System.String name)
{
return dir.FileLength(name);
}
}
}
}