Index: CHANGES.txt =================================================================== --- CHANGES.txt (revision 778176) +++ CHANGES.txt (working copy) @@ -321,6 +321,8 @@ 26. LUCENE-1550: Added new n-gram based String distance measure for spell checking. See the Javadocs for NGramDistance.java for a reference paper on why this is helpful (Tom Morton via Grant Ingersoll) +27. LUCENE-1658: Absorb NIOFSDirectory into FSDirectory, adding a + useNIO setting to FSDirectory. (Michael McCandless) Optimizations Index: src/test/org/apache/lucene/store/TestDirectory.java =================================================================== --- src/test/org/apache/lucene/store/TestDirectory.java (revision 778176) +++ src/test/org/apache/lucene/store/TestDirectory.java (working copy) @@ -53,8 +53,8 @@ int sz = 3; Directory[] dirs = new Directory[sz]; - dirs[0] = new FSDirectory(path, null); - dirs[1] = new NIOFSDirectory(path, null); + dirs[0] = new FSDirectory(path, null, false); + dirs[1] = new FSDirectory(path, null, true); dirs[2] = new MMapDirectory(path, null); for (int i=0; iIf useNIO is true, java.nio.* is used. This gives + * sizable gain in concurrent performance (when multiple + * threads are searching). Unfortuntely, on Windows it + * gives worse performance due to a known bug in Sun's + * JRE (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6265734). + * + * @param path the path of the directory + * @param lockFactory the lock factory to use, or null for the default. + * @param useNIO true if java.nio.* should be used + * @throws IOException + */ + public FSDirectory(File path, LockFactory lockFactory, boolean useNIO) throws IOException { path = getCanonicalPath(path); init(path, lockFactory); refCount = 1; + this.useNIO = useNIO; } private void init(File path, LockFactory lockFactory) throws IOException { @@ -559,7 +598,11 @@ // Inherit javadoc public IndexInput openInput(String name, int bufferSize) throws IOException { ensureOpen(); - return new FSIndexInput(new File(directory, name), bufferSize); + if (useNIO) { + return new NIOFSIndexInput(new File(directory, name), bufferSize); + } else { + return new FSIndexInput(new File(directory, name), bufferSize); + } } /** @@ -702,6 +745,76 @@ } } + // Used when useNIO is enabled + protected static class NIOFSIndexInput extends FSIndexInput { + + private ByteBuffer byteBuf; // wraps the buffer for NIO + + private byte[] otherBuffer; + private ByteBuffer otherByteBuf; + + final FileChannel channel; + + public NIOFSIndexInput(File path, int bufferSize) throws IOException { + super(path, bufferSize); + channel = file.getChannel(); + } + + protected void newBuffer(byte[] newBuffer) { + super.newBuffer(newBuffer); + byteBuf = ByteBuffer.wrap(newBuffer); + } + + public void close() throws IOException { + if (!isClone && file.isOpen) { + // Close the channel & file + try { + channel.close(); + } finally { + file.close(); + } + } + } + + protected void readInternal(byte[] b, int offset, int len) throws IOException { + + final ByteBuffer bb; + + // Determine the ByteBuffer we should use + if (b == buffer && 0 == offset) { + // Use our own pre-wrapped byteBuf: + assert byteBuf != null; + byteBuf.clear(); + byteBuf.limit(len); + bb = byteBuf; + } else { + if (offset == 0) { + if (otherBuffer != b) { + // Now wrap this other buffer; with compound + // file, we are repeatedly called with its + // buffer, so we wrap it once and then re-use it + // on subsequent calls + otherBuffer = b; + otherByteBuf = ByteBuffer.wrap(b); + } else + otherByteBuf.clear(); + otherByteBuf.limit(len); + bb = otherByteBuf; + } else + // Always wrap when offset != 0 + bb = ByteBuffer.wrap(b, offset, len); + } + + long pos = getFilePointer(); + while (bb.hasRemaining()) { + int i = channel.read(bb, pos); + if (i == -1) + throw new IOException("read past EOF"); + pos += i; + } + } + } + protected static class FSIndexOutput extends BufferedIndexOutput { RandomAccessFile file = null;