/* * 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; namespace Lucene.Net.Store { /// An {@link FSDirectory} implementation that uses /// java.nio's FileChannel's positional read, which allows /// multiple threads to read from the same file without /// synchronizing. /// ///

This class only uses FileChannel when reading; writing /// is achieved with {@link SimpleFSDirectory.SimpleFSIndexOutput}. /// ///

NOTE: NIOFSDirectory is not recommended on Windows because of a bug /// in how FileChannel.read is implemented in Sun's JRE. /// Inside of the implementation the position is apparently /// synchronized. See here /// for details. ///

public class NIOFSDirectory:FSDirectory { /// Create a new NIOFSDirectory for the named location. /// /// /// the path of the directory /// /// the lock factory to use, or null for the default. /// /// IOException [System.Obsolete("Use the constructor that takes a DirectoryInfo, this will be removed in the 3.0 release")] public NIOFSDirectory(System.IO.FileInfo path, LockFactory lockFactory):base(new System.IO.DirectoryInfo(path.FullName), lockFactory) { } /// Create a new NIOFSDirectory for the named location. /// /// /// the path of the directory /// /// the lock factory to use, or null for the default. /// /// IOException public NIOFSDirectory(System.IO.DirectoryInfo path, LockFactory lockFactory) : base(path, lockFactory) { } /// Create a new NIOFSDirectory for the named location and the default lock factory. /// /// /// the path of the directory /// /// IOException [System.Obsolete("Use the constructor that takes a DirectoryInfo, this will be removed in the 3.0 release")] public NIOFSDirectory(System.IO.FileInfo path):base(new System.IO.DirectoryInfo(path.FullName), null) { } /// Create a new NIOFSDirectory for the named location and the default lock factory. /// /// /// the path of the directory /// /// IOException public NIOFSDirectory(System.IO.DirectoryInfo path) : base(path, null) { } // back compatibility so FSDirectory can instantiate via reflection /// /// [Obsolete] internal NIOFSDirectory() { } /// Creates an IndexInput for the file with the given name. public override IndexInput OpenInput(System.String name, int bufferSize) { EnsureOpen(); return new NIOFSIndexInput(new System.IO.FileInfo(System.IO.Path.Combine(GetFile().FullName, name)), bufferSize, GetReadChunkSize()); } /// Creates an IndexOutput for the file with the given name. public override IndexOutput CreateOutput(System.String name) { InitOutput(name); return new SimpleFSDirectory.SimpleFSIndexOutput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name))); } public /*protected internal*/ class NIOFSIndexInput:SimpleFSDirectory.SimpleFSIndexInput { private System.IO.MemoryStream byteBuf; // wraps the buffer for NIO private byte[] otherBuffer; private System.IO.MemoryStream otherByteBuf; internal System.IO.BinaryReader channel; /// Please use ctor taking chunkSize /// [Obsolete("Please use ctor taking chunkSize")] public NIOFSIndexInput(System.IO.FileInfo path, int bufferSize):this(path, bufferSize, FSDirectory.DEFAULT_READ_CHUNK_SIZE) { } public NIOFSIndexInput(System.IO.FileInfo path, int bufferSize, int chunkSize):base(path, bufferSize, chunkSize) { channel = (System.IO.BinaryReader) file; } protected internal override void NewBuffer(byte[] newBuffer) { base.NewBuffer(newBuffer); // {{Aroush-2.9}} byteBuf = ByteBuffer.wrap(newBuffer); System.Diagnostics.Debug.Fail("Port issue:", "byteBuf = ByteBuffer.wrap(newBuffer)"); // {{Aroush-2.9}} } public override void Close() { if (!isClone && file.isOpen) { // Close the channel & file try { channel.Close(); } finally { file.Close(); } } } public override void ReadInternal(byte[] b, int offset, int len) { System.IO.MemoryStream bb; // Determine the ByteBuffer we should use if (b == buffer && 0 == offset) { // Use our own pre-wrapped byteBuf: System.Diagnostics.Debug.Assert(byteBuf != null); byteBuf.Position = 0; byteBuf.Capacity = 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); {{Aroush-2.9}} System.Diagnostics.Debug.Fail("Port issue:", "otherByteBuf = ByteBuffer.wrap(b)"); // {{Aroush-2.9}} } else otherByteBuf.Position = 0; otherByteBuf.Capacity = len; bb = otherByteBuf; } else { // Always wrap when offset != 0 bb = null; // bb = ByteBuffer.wrap(b, offset, len); {{Aroush-2.9}} System.Diagnostics.Debug.Fail("Port issue:", "bb = ByteBuffer.wrap(b, offset, len)"); // {{Aroush-2.9}} } } int readOffset = (int) bb.Position; int readLength = bb.Capacity - readOffset; System.Diagnostics.Debug.Assert(readLength == len); long pos = GetFilePointer(); try { while (readLength > 0) { int limit; if (readLength > chunkSize) { // LUCENE-1566 - work around JVM Bug by breaking // very large reads into chunks limit = readOffset + chunkSize; } else { limit = readOffset + readLength; } bb.Capacity = limit; int i = -1; // int i = channel.Read(bb, pos, limit); // {{Aroush-2.9}} must read from 'channel' into 'bb' System.Diagnostics.Debug.Fail("Port issue:", "channel.Read(bb, pos, limit)"); // {{Aroush-2.9}} if (i == - 1) { throw new System.IO.IOException("read past EOF"); } pos += i; readOffset += i; readLength -= i; } } catch (System.OutOfMemoryException e) { // propagate OOM up and add a hint for 32bit VM Users hitting the bug // with a large chunk size in the fast path. System.OutOfMemoryException outOfMemoryError = new System.OutOfMemoryException("OutOfMemoryError likely caused by the Sun VM Bug described in " + "https://issues.apache.org/jira/browse/LUCENE-1566; try calling FSDirectory.setReadChunkSize " + "with a a value smaller than the current chunk size (" + chunkSize + ")", e); throw outOfMemoryError; } } } } }