blob: 188ad4b88c42a89b8271247c928f47277efdf022 [file] [log] [blame]
using Lucene.Net.Documents;
using Lucene.Net.Index.Extensions;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Assert = Lucene.Net.TestFramework.Assert;
namespace Lucene.Net.Store
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ArrayUtil = Lucene.Net.Util.ArrayUtil;
using DirectoryReader = Lucene.Net.Index.DirectoryReader;
using Document = Documents.Document;
using Field = Field;
using IndexReader = Lucene.Net.Index.IndexReader;
using IndexWriter = Lucene.Net.Index.IndexWriter;
using IndexWriterConfig = Lucene.Net.Index.IndexWriterConfig;
using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
using OpenMode = Lucene.Net.Index.OpenMode;
using Term = Lucene.Net.Index.Term;
using TermQuery = Lucene.Net.Search.TermQuery;
[TestFixture]
public class TestBufferedIndexInput : LuceneTestCase
{
private static void WriteBytes(FileInfo aFile, long size)
{
using FileStream ostream = new FileStream(aFile.FullName, FileMode.Create);
for (int i = 0; i < size; i++)
{
ostream.WriteByte(Byten(i));
}
ostream.Flush();
}
private const long TEST_FILE_LENGTH = 100 * 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()
{
MyBufferedIndexInput input = new MyBufferedIndexInput();
RunReadBytes(input, BufferedIndexInput.BUFFER_SIZE, Random);
}
private void RunReadBytesAndClose(IndexInput input, int bufferSize, Random r)
{
try
{
RunReadBytes(input, bufferSize, r);
}
finally
{
input.Dispose();
}
}
private void RunReadBytes(IndexInput input, int bufferSize, 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 < 100; 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.GetFilePointer());
long left = TEST_FILE_LENGTH - input.GetFilePointer();
if (left <= 0)
{
return;
}
else if (left < size)
{
size = (int)left;
}
input.ReadBytes(buffer, offset, size);
Assert.AreEqual(pos + size, input.GetFilePointer());
for (int i = 0; i < size; i++)
{
Assert.AreEqual(Byten(pos + i), (byte)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);
try
{
CheckReadBytes(input, 11, pos);
Assert.Fail("Block read past end of file");
}
#pragma warning disable 168
catch (IOException e)
#pragma warning restore 168
{
/* success */
}
input.Seek(pos);
try
{
CheckReadBytes(input, 50, pos);
Assert.Fail("Block read past end of file");
}
#pragma warning disable 168
catch (IOException e)
#pragma warning restore 168
{
/* success */
}
input.Seek(pos);
try
{
CheckReadBytes(input, 100000, pos);
Assert.Fail("Block read past end of file");
}
#pragma warning disable 168
catch (IOException e)
#pragma warning restore 168
{
/* success */
}
}
// 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 readonly long len;
public MyBufferedIndexInput(long len)
: base("MyBufferedIndexInput(len=" + len + ")", BufferedIndexInput.BUFFER_SIZE)
{
this.len = len;
this.pos = 0;
}
public MyBufferedIndexInput()
: this(long.MaxValue)
{
// an infinite file
}
protected override void ReadInternal(byte[] b, int offset, int length)
{
for (int i = offset; i < offset + length; i++)
{
b[i] = Byten(pos++);
}
}
protected override void SeekInternal(long pos)
{
this.pos = pos;
}
protected override void Dispose(bool disposing)
{
}
public override long Length => len;
}
[Test]
public virtual void TestSetBufferSize()
{
var indexDir = CreateTempDir("testSetBufferSize");
var dir = new MockFSDirectory(indexDir, Random);
try
{
var writer = new IndexWriter(
dir,
new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random))
.SetOpenMode(OpenMode.CREATE)
.SetMergePolicy(NewLogMergePolicy(false)));
for (int i = 0; i < 37; i++)
{
var doc = new Document();
doc.Add(NewTextField("content", "aaa bbb ccc ddd" + i, Field.Store.YES));
doc.Add(NewTextField("id", "" + i, Field.Store.YES));
writer.AddDocument(doc);
}
dir.allIndexInputs.Clear();
IndexReader reader = DirectoryReader.Open(writer, true);
var aaa = new Term("content", "aaa");
var bbb = new Term("content", "bbb");
reader.Dispose();
dir.TweakBufferSizes();
writer.DeleteDocuments(new Term("id", "0"));
reader = DirectoryReader.Open(writer, true);
var searcher = NewSearcher(reader);
var hits = searcher.Search(new TermQuery(bbb), null, 1000).ScoreDocs;
dir.TweakBufferSizes();
Assert.AreEqual(36, hits.Length);
reader.Dispose();
dir.TweakBufferSizes();
writer.DeleteDocuments(new Term("id", "4"));
reader = DirectoryReader.Open(writer, true);
searcher = NewSearcher(reader);
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);
writer.Dispose();
reader.Dispose();
}
finally
{
indexDir.Delete(true);
}
}
private class MockFSDirectory : BaseDirectory
{
internal readonly IList<IndexInput> allIndexInputs = new List<IndexInput>();
private readonly Random rand;
private readonly Directory dir;
public MockFSDirectory(DirectoryInfo path, Random rand)
{
this.rand = rand;
SetLockFactory(NoLockFactory.GetNoLockFactory());
dir = new SimpleFSDirectory(path, null);
}
public virtual void TweakBufferSizes()
{
//int count = 0;
foreach (IndexInput ip in allIndexInputs)
{
BufferedIndexInput bii = (BufferedIndexInput)ip;
int bufferSize = 1024 + Math.Abs(rand.Next() % 32768);
bii.SetBufferSize(bufferSize);
//count++;
}
//System.out.println("tweak'd " + count + " buffer sizes");
}
public override IndexInput OpenInput(string name, IOContext context)
{
// Make random changes to buffer size
//bufferSize = 1+Math.abs(rand.nextInt() % 10);
IndexInput f = dir.OpenInput(name, context);
allIndexInputs.Add(f);
return f;
}
public override IndexOutput CreateOutput(string name, IOContext context)
{
return dir.CreateOutput(name, context);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
dir.Dispose();
}
}
public override void DeleteFile(string name)
{
dir.DeleteFile(name);
}
[Obsolete("this method will be removed in 5.0")]
public override bool FileExists(string name)
{
return dir.FileExists(name);
}
public override string[] ListAll()
{
return dir.ListAll();
}
public override void Sync(ICollection<string> names)
{
dir.Sync(names);
}
public override long FileLength(string name)
{
return dir.FileLength(name);
}
}
}
}