This is an automated email from the ASF dual-hosted git repository. nightowl888 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/lucenenet.git
commit 5da2567ea771538a31566918066d01bde3b6af0f Author: Shad Storhaug <[email protected]> AuthorDate: Fri Feb 7 12:38:54 2020 +0700 Lucene.Net.Support.IO.FileStreamExtensions::Read(): Moved to StreamExtensions class and optimized to read bytes in bulk instead of one byte at a time (fixes LUCENENET-643) --- src/Lucene.Net/Store/NIOFSDirectory.cs | 4 +- src/Lucene.Net/Support/IO/FileStreamExtensions.cs | 57 ------------ src/Lucene.Net/Support/IO/StreamExtensions.cs | 107 +++++++++++++++++++++- 3 files changed, 108 insertions(+), 60 deletions(-) diff --git a/src/Lucene.Net/Store/NIOFSDirectory.cs b/src/Lucene.Net/Store/NIOFSDirectory.cs index 8842766..d49625e 100644 --- a/src/Lucene.Net/Store/NIOFSDirectory.cs +++ b/src/Lucene.Net/Store/NIOFSDirectory.cs @@ -158,8 +158,8 @@ namespace Lucene.Net.Store } /// <summary> - /// Reads bytes with the <see cref="FileStreamExtensions.Read(FileStream, ByteBuffer, long)"/> - /// extension method for <see cref="FileStream"/>. + /// Reads bytes with the <see cref="StreamExtensions.Read(Stream, ByteBuffer, long)"/> + /// extension method for <see cref="Stream"/>. /// </summary> protected class NIOFSIndexInput : BufferedIndexInput { diff --git a/src/Lucene.Net/Support/IO/FileStreamExtensions.cs b/src/Lucene.Net/Support/IO/FileStreamExtensions.cs deleted file mode 100644 index cec1efd..0000000 --- a/src/Lucene.Net/Support/IO/FileStreamExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -using J2N.IO; -using System.IO; - -namespace Lucene.Net.Support.IO -{ - /* - * 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. - */ - - internal static class FileStreamExtensions - { - private static object _fsReadLock = new object(); - - //Reads bytes from the Filestream into the bytebuffer - public static int Read(this FileStream file, ByteBuffer dst, long position) - { - lock (_fsReadLock) - { - // TODO: check this logic, could probably optimize - if (position >= file.Length) - return 0; - - var original = file.Position; - - file.Seek(position, SeekOrigin.Begin); - - int count = 0; - - for (int i = dst.Position; i < dst.Limit; i++) - { - int v = file.ReadByte(); - if (v == -1) - break; - dst.Put((byte) v); - count++; - } - - file.Seek(original, SeekOrigin.Begin); - - return count; - } - } - } -} \ No newline at end of file diff --git a/src/Lucene.Net/Support/IO/StreamExtensions.cs b/src/Lucene.Net/Support/IO/StreamExtensions.cs index f8c8531..2a4d5ca 100644 --- a/src/Lucene.Net/Support/IO/StreamExtensions.cs +++ b/src/Lucene.Net/Support/IO/StreamExtensions.cs @@ -1,4 +1,6 @@ -using System.IO; +using J2N.IO; +using System; +using System.IO; namespace Lucene.Net.Support.IO { @@ -32,8 +34,94 @@ namespace Lucene.Net.Support.IO /// </summary> internal static class StreamExtensions { + private static readonly object readLock = new object(); + + + /// <summary> + /// Reads a sequence of bytes from a <see cref="Stream"/> to the given <see cref="ByteBuffer"/>, starting at the given position. + /// The <paramref name="stream"/> must be both seekable and readable. + /// </summary> + /// <param name="stream">The stream to read.</param> + /// <param name="destination">The <see cref="ByteBuffer"/> to write to.</param> + /// <param name="position">The file position at which the transfer is to begin; must be non-negative.</param> + /// <returns>The number of bytes read, possibly zero.</returns> + /// <exception cref="ArgumentNullException"><paramref name="stream"/> or <paramref name="destination"/> is <c>null</c></exception> + /// <exception cref="NotSupportedException"> + /// <paramref name="stream"/> is not readable. + /// <para/> + /// -or- + /// <para/> + /// <paramref name="stream"/> is not seekable. + /// </exception> + /// <exception cref="ArgumentOutOfRangeException"> + /// <paramref name="position"/> is less than 0. + /// <para/> + /// -or- + /// <para/> + /// <paramref name="position"/> is greater than the <see cref="Stream.Length"/> of the stream. + /// </exception> + /// <exception cref="IOException">An I/O error occurs.</exception> + /// <exception cref="ObjectDisposedException"><paramref name="stream"/> has already been disposed.</exception> + /// <remarks> + /// This method is atomic when used by itself, but does not synchronize with the rest of the stream methods. + /// </remarks> + public static int Read(this Stream stream, ByteBuffer destination, long position) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (destination == null) + throw new ArgumentNullException(nameof(destination)); + if (position < 0) + throw new ArgumentOutOfRangeException(nameof(position)); + if (!stream.CanSeek) + throw new NotSupportedException("Stream does not support seeking."); + if (!stream.CanRead) + throw new NotSupportedException("Stream does not support reading."); + if (position > stream.Length) + return 0; + + int read = 0; + lock (readLock) + { + long originalPosition = stream.Position; + stream.Seek(position, SeekOrigin.Begin); + + if (destination.HasArray) + { + // If the buffer has an array, we can write to it directly and save + // an extra copy operation. + + // Read from the stream + read = stream.Read(destination.Array, destination.Position, destination.Remaining); + destination.Position += read; + } + else + { + // If the buffer has no array, we must use a local buffer + byte[] buffer = new byte[destination.Remaining]; + + // Read from the stream + read = stream.Read(buffer, 0, buffer.Length); + + // Write to the byte buffer + destination.Put(buffer, 0, read); + } + + // Per Java's FileChannel.Read(), we don't want to alter the position + // of the stream, so we return it as it was originally. + stream.Seek(originalPosition, SeekOrigin.Begin); + } + + return read; + } + public static void Write(this Stream stream, char[] chars) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (chars == null) + throw new ArgumentNullException(nameof(chars)); + byte[] newBytes = new byte[chars.Length * 2]; for (int index = 0; index < chars.Length; index++) { @@ -46,6 +134,11 @@ namespace Lucene.Net.Support.IO public static char[] ReadChars(this Stream stream, int count) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + byte[] buff = new byte[2]; char[] newChars = new char[count]; for (int i = 0; i < count; i++) @@ -58,6 +151,9 @@ namespace Lucene.Net.Support.IO public static void Write(this Stream stream, int value) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + byte[] buff = new byte[4]; buff[0] = (byte)(value); buff[1] = (byte)(value >> 8); @@ -68,6 +164,9 @@ namespace Lucene.Net.Support.IO public static int ReadInt32(this Stream stream) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + byte[] buff = new byte[4]; stream.Read(buff, 0, buff.Length); return (buff[0] & 0xff) | ((buff[1] & 0xff) << 8) | @@ -76,6 +175,9 @@ namespace Lucene.Net.Support.IO public static void Write(this Stream stream, long value) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + byte[] buff = new byte[8]; buff[0] = (byte)value; buff[1] = (byte)(value >> 8); @@ -90,6 +192,9 @@ namespace Lucene.Net.Support.IO public static long ReadInt64(this Stream stream) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + byte[] buff = new byte[8]; stream.Read(buff, 0, buff.Length); uint lo = (uint)(buff[0] | buff[1] << 8 |
