FileDocCategorySizeDatePackage
TestBufferedIndexInput.javaAPI DocApache Lucene 2.2.09604Sat Jun 16 22:20:24 BST 2007org.apache.lucene.store

TestBufferedIndexInput.java

package org.apache.lucene.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.
 */

import java.io.IOException;
import java.io.File;
import java.util.List;
import java.util.Random;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util._TestUtil;

import junit.framework.TestCase;

public class TestBufferedIndexInput extends TestCase {
	// 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.
    public void testReadByte() throws Exception {
    	MyBufferedIndexInput input = new MyBufferedIndexInput(); 
    	for(int i=0; i<BufferedIndexInput.BUFFER_SIZE*10; i++){
     		assertEquals(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.
    public void testReadBytes() throws Exception {
    	MyBufferedIndexInput input = new MyBufferedIndexInput();
    	int pos=0;
    	// gradually increasing size:
    	for(int size=1; size<BufferedIndexInput.BUFFER_SIZE*10; size=size+size/200+1){
    		checkReadBytes(input, size, pos);
    		pos+=size;
    	}
    	// wildly fluctuating size:
    	for(long i=0; i<1000; i++){
    		// The following function generates a fluctuating (but repeatable)
    		// size, sometimes small (<100) but sometimes large (>10000)
    		int size1 = (int)( i%7 + 7*(i%5)+ 7*5*(i%3) + 5*5*3*(i%2));
    		int size2 = (int)( i%11 + 11*(i%7)+ 11*7*(i%5) + 11*7*5*(i%3) + 11*7*5*3*(i%2) );
    		int size = (i%3==0)?size2*10:size1; 
    		checkReadBytes(input, size, pos);
    		pos+=size;
    	}
    	// constant small size (7 bytes):
    	for(int i=0; i<BufferedIndexInput.BUFFER_SIZE; i++){
    		checkReadBytes(input, 7, pos);
    		pos+=7;
    	}
    }
   private void checkReadBytes(BufferedIndexInput input, int size, int pos) throws IOException{
	   // 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
	   byte[] b = new byte[offset+size];
	   input.readBytes(b, offset, size);
	   for(int i=0; i<size; i++){
		   assertEquals(b[offset+i], byten(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.
   public void testEOF() throws Exception {
	   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);
           fail("Block read past end of file");
       } catch (IOException e) {
           /* success */
       }
	   input.seek(pos);
	   try {
		   checkReadBytes(input, 50, pos);
           fail("Block read past end of file");
       } catch (IOException e) {
           /* success */
       }
	   input.seek(pos);
	   try {
		   checkReadBytes(input, 100000, pos);
           fail("Block read past end of file");
       } catch (IOException e) {
           /* 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 static class MyBufferedIndexInput extends BufferedIndexInput {
    	private long pos;
    	private long len;
    	public MyBufferedIndexInput(long len){
    		this.len = len;
    		this.pos = 0;
    	}
    	public MyBufferedIndexInput(){
    		// an infinite file
    		this(Long.MAX_VALUE);
    	}
		protected void readInternal(byte[] b, int offset, int length) throws IOException {
			for(int i=offset; i<offset+length; i++)
				b[i] = byten(pos++);
		}

		protected void seekInternal(long pos) throws IOException {
			this.pos = pos;
		}

		public void close() throws IOException {
		}

		public long length() {
			return len;
		}
    }

    public void testSetBufferSize() throws IOException {
      File indexDir = new File(System.getProperty("tempDir"), "testSetBufferSize");
      MockFSDirectory dir = new MockFSDirectory(indexDir);
      try {
        IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true);
        writer.setUseCompoundFile(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.TOKENIZED));
          doc.add(new Field("id", "" + i, Field.Store.YES, Field.Index.TOKENIZED));
          writer.addDocument(doc);
        }
        writer.close();

        dir.allIndexInputs.clear();

        IndexReader reader = IndexReader.open(dir);
        Term aaa = new Term("content", "aaa");
        Term bbb = new Term("content", "bbb");
        Term ccc = new Term("content", "ccc");
        assertEquals(reader.docFreq(ccc), 37);
        reader.deleteDocument(0);
        assertEquals(reader.docFreq(aaa), 37);
        dir.tweakBufferSizes();
        reader.deleteDocument(4);
        assertEquals(reader.docFreq(bbb), 37);
        dir.tweakBufferSizes();

        IndexSearcher searcher = new IndexSearcher(reader);
        Hits hits = searcher.search(new TermQuery(bbb));
        dir.tweakBufferSizes();
        assertEquals(35, hits.length());
        dir.tweakBufferSizes();
        hits = searcher.search(new TermQuery(new Term("id", "33")));
        dir.tweakBufferSizes();
        assertEquals(1, hits.length());
        hits = searcher.search(new TermQuery(aaa));
        dir.tweakBufferSizes();
        assertEquals(35, hits.length());
        searcher.close();
        reader.close();
      } finally {
        _TestUtil.rmDir(indexDir);
      }
    }

    private static class MockFSDirectory extends Directory {

      List allIndexInputs = new ArrayList();

      Random rand = new Random();

      private Directory dir;

      public MockFSDirectory(File path) throws IOException {
        lockFactory = new NoLockFactory();
        dir = FSDirectory.getDirectory(path);
      }

      public IndexInput openInput(String name) throws IOException {
        return openInput(name, BufferedIndexInput.BUFFER_SIZE);
      }

      public void tweakBufferSizes() {
        Iterator it = allIndexInputs.iterator();
        int count = 0;
        while(it.hasNext()) {
          BufferedIndexInput bii = (BufferedIndexInput) it.next();
          int bufferSize = 1024+(int) Math.abs(rand.nextInt() % 32768);
          bii.setBufferSize(bufferSize);
          count++;
        }
        //System.out.println("tweak'd " + count + " buffer sizes");
      }
      
      public IndexInput openInput(String name, int bufferSize) throws IOException {
        // Make random changes to buffer size
        bufferSize = 1+(int) Math.abs(rand.nextInt() % 10);
        IndexInput f = dir.openInput(name, bufferSize);
        allIndexInputs.add(f);
        return f;
      }

      public IndexOutput createOutput(String name) throws IOException {
        return dir.createOutput(name);
      }

      public void close() throws IOException {
        dir.close();
      }

      public void deleteFile(String name)
        throws IOException
      {
        dir.deleteFile(name);
      }
      public void touchFile(String name)
        throws IOException
      {
        dir.touchFile(name);
      }
      public long fileModified(String name)
        throws IOException
      {
        return dir.fileModified(name);
      }
      public boolean fileExists(String name)
        throws IOException
      {
        return dir.fileExists(name);
      }
      public String[] list()
        throws IOException
      {
        return dir.list();
      }

      public long fileLength(String name) throws IOException {
        return dir.fileLength(name);
      }
      public void renameFile(String from, String to)
        throws IOException
      {
        dir.renameFile(from, to);
      }


    }
}