001: package org.apache.lucene.store;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.IOException;
021: import java.io.File;
022: import java.util.List;
023: import java.util.Random;
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import org.apache.lucene.index.IndexWriter;
027: import org.apache.lucene.index.IndexReader;
028: import org.apache.lucene.index.Term;
029: import org.apache.lucene.search.IndexSearcher;
030: import org.apache.lucene.analysis.WhitespaceAnalyzer;
031: import org.apache.lucene.document.Document;
032: import org.apache.lucene.document.Field;
033: import org.apache.lucene.search.Hits;
034: import org.apache.lucene.search.TermQuery;
035: import org.apache.lucene.util._TestUtil;
036:
037: import org.apache.lucene.util.LuceneTestCase;
038:
039: public class TestBufferedIndexInput extends LuceneTestCase {
040: // Call readByte() repeatedly, past the buffer boundary, and see that it
041: // is working as expected.
042: // Our input comes from a dynamically generated/ "file" - see
043: // MyBufferedIndexInput below.
044: public void testReadByte() throws Exception {
045: MyBufferedIndexInput input = new MyBufferedIndexInput();
046: for (int i = 0; i < BufferedIndexInput.BUFFER_SIZE * 10; i++) {
047: assertEquals(input.readByte(), byten(i));
048: }
049: }
050:
051: // Call readBytes() repeatedly, with various chunk sizes (from 1 byte to
052: // larger than the buffer size), and see that it returns the bytes we expect.
053: // Our input comes from a dynamically generated "file" -
054: // see MyBufferedIndexInput below.
055: public void testReadBytes() throws Exception {
056: MyBufferedIndexInput input = new MyBufferedIndexInput();
057: int pos = 0;
058: // gradually increasing size:
059: for (int size = 1; size < BufferedIndexInput.BUFFER_SIZE * 10; size = size
060: + size / 200 + 1) {
061: checkReadBytes(input, size, pos);
062: pos += size;
063: }
064: // wildly fluctuating size:
065: for (long i = 0; i < 1000; i++) {
066: // The following function generates a fluctuating (but repeatable)
067: // size, sometimes small (<100) but sometimes large (>10000)
068: int size1 = (int) (i % 7 + 7 * (i % 5) + 7 * 5 * (i % 3) + 5 * 5 * 3 * (i % 2));
069: int size2 = (int) (i % 11 + 11 * (i % 7) + 11 * 7 * (i % 5)
070: + 11 * 7 * 5 * (i % 3) + 11 * 7 * 5 * 3 * (i % 2));
071: int size = (i % 3 == 0) ? size2 * 10 : size1;
072: checkReadBytes(input, size, pos);
073: pos += size;
074: }
075: // constant small size (7 bytes):
076: for (int i = 0; i < BufferedIndexInput.BUFFER_SIZE; i++) {
077: checkReadBytes(input, 7, pos);
078: pos += 7;
079: }
080: }
081:
082: private void checkReadBytes(BufferedIndexInput input, int size,
083: int pos) throws IOException {
084: // Just to see that "offset" is treated properly in readBytes(), we
085: // add an arbitrary offset at the beginning of the array
086: int offset = size % 10; // arbitrary
087: byte[] b = new byte[offset + size];
088: input.readBytes(b, offset, size);
089: for (int i = 0; i < size; i++) {
090: assertEquals(b[offset + i], byten(pos + i));
091: }
092: }
093:
094: // This tests that attempts to readBytes() past an EOF will fail, while
095: // reads up to the EOF will succeed. The EOF is determined by the
096: // BufferedIndexInput's arbitrary length() value.
097: public void testEOF() throws Exception {
098: MyBufferedIndexInput input = new MyBufferedIndexInput(1024);
099: // see that we can read all the bytes at one go:
100: checkReadBytes(input, (int) input.length(), 0);
101: // go back and see that we can't read more than that, for small and
102: // large overflows:
103: int pos = (int) input.length() - 10;
104: input.seek(pos);
105: checkReadBytes(input, 10, pos);
106: input.seek(pos);
107: try {
108: checkReadBytes(input, 11, pos);
109: fail("Block read past end of file");
110: } catch (IOException e) {
111: /* success */
112: }
113: input.seek(pos);
114: try {
115: checkReadBytes(input, 50, pos);
116: fail("Block read past end of file");
117: } catch (IOException e) {
118: /* success */
119: }
120: input.seek(pos);
121: try {
122: checkReadBytes(input, 100000, pos);
123: fail("Block read past end of file");
124: } catch (IOException e) {
125: /* success */
126: }
127: }
128:
129: // byten emulates a file - byten(n) returns the n'th byte in that file.
130: // MyBufferedIndexInput reads this "file".
131: private static byte byten(long n) {
132: return (byte) (n * n % 256);
133: }
134:
135: private static class MyBufferedIndexInput extends
136: BufferedIndexInput {
137: private long pos;
138: private long len;
139:
140: public MyBufferedIndexInput(long len) {
141: this .len = len;
142: this .pos = 0;
143: }
144:
145: public MyBufferedIndexInput() {
146: // an infinite file
147: this (Long.MAX_VALUE);
148: }
149:
150: protected void readInternal(byte[] b, int offset, int length)
151: throws IOException {
152: for (int i = offset; i < offset + length; i++)
153: b[i] = byten(pos++);
154: }
155:
156: protected void seekInternal(long pos) throws IOException {
157: this .pos = pos;
158: }
159:
160: public void close() throws IOException {
161: }
162:
163: public long length() {
164: return len;
165: }
166: }
167:
168: public void testSetBufferSize() throws IOException {
169: File indexDir = new File(System.getProperty("tempDir"),
170: "testSetBufferSize");
171: MockFSDirectory dir = new MockFSDirectory(indexDir);
172: try {
173: IndexWriter writer = new IndexWriter(dir,
174: new WhitespaceAnalyzer(), true);
175: writer.setUseCompoundFile(false);
176: for (int i = 0; i < 37; i++) {
177: Document doc = new Document();
178: doc.add(new Field("content", "aaa bbb ccc ddd" + i,
179: Field.Store.YES, Field.Index.TOKENIZED));
180: doc.add(new Field("id", "" + i, Field.Store.YES,
181: Field.Index.TOKENIZED));
182: writer.addDocument(doc);
183: }
184: writer.close();
185:
186: dir.allIndexInputs.clear();
187:
188: IndexReader reader = IndexReader.open(dir);
189: Term aaa = new Term("content", "aaa");
190: Term bbb = new Term("content", "bbb");
191: Term ccc = new Term("content", "ccc");
192: assertEquals(reader.docFreq(ccc), 37);
193: reader.deleteDocument(0);
194: assertEquals(reader.docFreq(aaa), 37);
195: dir.tweakBufferSizes();
196: reader.deleteDocument(4);
197: assertEquals(reader.docFreq(bbb), 37);
198: dir.tweakBufferSizes();
199:
200: IndexSearcher searcher = new IndexSearcher(reader);
201: Hits hits = searcher.search(new TermQuery(bbb));
202: dir.tweakBufferSizes();
203: assertEquals(35, hits.length());
204: dir.tweakBufferSizes();
205: hits = searcher.search(new TermQuery(new Term("id", "33")));
206: dir.tweakBufferSizes();
207: assertEquals(1, hits.length());
208: hits = searcher.search(new TermQuery(aaa));
209: dir.tweakBufferSizes();
210: assertEquals(35, hits.length());
211: searcher.close();
212: reader.close();
213: } finally {
214: _TestUtil.rmDir(indexDir);
215: }
216: }
217:
218: private static class MockFSDirectory extends Directory {
219:
220: List allIndexInputs = new ArrayList();
221:
222: Random rand = new Random();
223:
224: private Directory dir;
225:
226: public MockFSDirectory(File path) throws IOException {
227: lockFactory = new NoLockFactory();
228: dir = FSDirectory.getDirectory(path);
229: }
230:
231: public IndexInput openInput(String name) throws IOException {
232: return openInput(name, BufferedIndexInput.BUFFER_SIZE);
233: }
234:
235: public void tweakBufferSizes() {
236: Iterator it = allIndexInputs.iterator();
237: int count = 0;
238: while (it.hasNext()) {
239: BufferedIndexInput bii = (BufferedIndexInput) it.next();
240: int bufferSize = 1024 + (int) Math
241: .abs(rand.nextInt() % 32768);
242: bii.setBufferSize(bufferSize);
243: count++;
244: }
245: //System.out.println("tweak'd " + count + " buffer sizes");
246: }
247:
248: public IndexInput openInput(String name, int bufferSize)
249: throws IOException {
250: // Make random changes to buffer size
251: bufferSize = 1 + (int) Math.abs(rand.nextInt() % 10);
252: IndexInput f = dir.openInput(name, bufferSize);
253: allIndexInputs.add(f);
254: return f;
255: }
256:
257: public IndexOutput createOutput(String name) throws IOException {
258: return dir.createOutput(name);
259: }
260:
261: public void close() throws IOException {
262: dir.close();
263: }
264:
265: public void deleteFile(String name) throws IOException {
266: dir.deleteFile(name);
267: }
268:
269: public void touchFile(String name) throws IOException {
270: dir.touchFile(name);
271: }
272:
273: public long fileModified(String name) throws IOException {
274: return dir.fileModified(name);
275: }
276:
277: public boolean fileExists(String name) throws IOException {
278: return dir.fileExists(name);
279: }
280:
281: public String[] list() throws IOException {
282: return dir.list();
283: }
284:
285: public long fileLength(String name) throws IOException {
286: return dir.fileLength(name);
287: }
288:
289: public void renameFile(String from, String to)
290: throws IOException {
291: dir.renameFile(from, to);
292: }
293:
294: }
295: }
|