You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2020/02/09 06:16:25 UTC

[lucenenet] 33/35: 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)

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 <sh...@shadstorhaug.com>
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 |