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 08e35ce8ae4ed5d47da37bf1157ad3a17928cc98
Author: Shad Storhaug <s...@shadstorhaug.com>
AuthorDate: Tue Feb 11 16:57:53 2020 +0700

    Lucene.Net.Store (FSDirectory + BufferedIndexOutput): Refactored 
FSDirectory.FSIndexOutput to utilize the FileStream buffer only, rather than 
using both a FileStream buffer and the buffer in BufferedIndexOutput.
---
 src/Lucene.Net/Store/BufferedIndexOutput.cs | 27 ++++++-----
 src/Lucene.Net/Store/FSDirectory.cs         | 75 +++++++++++++++++++++++------
 2 files changed, 74 insertions(+), 28 deletions(-)

diff --git a/src/Lucene.Net/Store/BufferedIndexOutput.cs 
b/src/Lucene.Net/Store/BufferedIndexOutput.cs
index 6f3f12d..4b59b01 100644
--- a/src/Lucene.Net/Store/BufferedIndexOutput.cs
+++ b/src/Lucene.Net/Store/BufferedIndexOutput.cs
@@ -30,10 +30,10 @@ namespace Lucene.Net.Store
         public const int DEFAULT_BUFFER_SIZE = 16384;
 
         private readonly int bufferSize;
-        private readonly byte[] buffer;
+        private byte[] buffer;
         private long bufferStart = 0; // position in file of buffer
         private int bufferPosition = 0; // position in buffer
-        private readonly CRC32 crc = new CRC32();
+        private readonly CRC32 crc;
 
         /// <summary>
         /// Creates a new <see cref="BufferedIndexOutput"/> with the default 
buffer size
@@ -48,18 +48,24 @@ namespace Lucene.Net.Store
         /// Creates a new <see cref="BufferedIndexOutput"/> with the given 
buffer size. </summary>
         /// <param name="bufferSize"> the buffer size in bytes used to buffer 
writes internally. </param>
         /// <exception cref="ArgumentException"> if the given buffer size is 
less or equal to <c>0</c> </exception>
-        public BufferedIndexOutput(int bufferSize)
+        public BufferedIndexOutput(int bufferSize) : this(bufferSize, new 
CRC32()) { }
+
+        // LUCENENET specific - added constructor overload so FSDirectory can 
still subclass BufferedIndexOutput, but
+        // utilize its own buffer, since FileStream is already buffered in 
.NET.
+        internal BufferedIndexOutput(int bufferSize, CRC32 crc)
         {
             if (bufferSize <= 0)
             {
                 throw new ArgumentException("bufferSize must be greater than 0 
(got " + bufferSize + ")");
             }
             this.bufferSize = bufferSize;
-            buffer = new byte[bufferSize];
+            // LUCENENET: We lazy-load the buffer, so we don't force all 
subclasses to allocate it
+            this.crc = crc;
         }
 
         public override void WriteByte(byte b)
         {
+            if (buffer == null) buffer = new byte[bufferSize]; // LUCENENET: 
Lazy-load the buffer, so we don't force all subclasses to allocate it
             if (bufferPosition >= bufferSize)
             {
                 Flush();
@@ -69,6 +75,7 @@ namespace Lucene.Net.Store
 
         public override void WriteBytes(byte[] b, int offset, int length)
         {
+            if (buffer == null) buffer = new byte[bufferSize]; // LUCENENET: 
Lazy-load the buffer, so we don't force all subclasses to allocate it
             int bytesLeft = bufferSize - bufferPosition;
             // is there enough space in the buffer?
             if (bytesLeft >= length)
@@ -120,9 +127,11 @@ namespace Lucene.Net.Store
             }
         }
 
+        /// <inheritdoc/>
         [MethodImpl(MethodImplOptions.NoInlining)]
         public override void Flush()
         {
+            if (buffer == null) return; // LUCENENET: Lazy-load the buffer, so 
we don't force all subclasses to allocate it
             crc.Update(buffer, 0, bufferPosition);
             FlushBuffer(buffer, bufferPosition);
             bufferStart += bufferPosition;
@@ -147,6 +156,7 @@ namespace Lucene.Net.Store
         /// <param name="len"> the number of bytes to write </param>
         protected internal abstract void FlushBuffer(byte[] b, int offset, int 
len);
 
+        /// <inheritdoc/>
         protected override void Dispose(bool disposing)
         {
             if (disposing)
@@ -171,15 +181,8 @@ namespace Lucene.Net.Store
 
         /// <summary>
         /// Returns size of the used output buffer in bytes.
-        ///
         /// </summary>
-        public int BufferSize
-        {
-            get
-            {
-                return bufferSize;
-            }
-        }
+        public int BufferSize => bufferSize;
 
         public override long Checksum
         {
diff --git a/src/Lucene.Net/Store/FSDirectory.cs 
b/src/Lucene.Net/Store/FSDirectory.cs
index a07021e..00ddcd3 100644
--- a/src/Lucene.Net/Store/FSDirectory.cs
+++ b/src/Lucene.Net/Store/FSDirectory.cs
@@ -1,3 +1,4 @@
+using Lucene.Net.Support;
 using Lucene.Net.Support.IO;
 using System;
 using System.Collections.Generic;
@@ -5,6 +6,7 @@ using System.Diagnostics;
 using System.Globalization;
 using System.IO;
 using System.Linq;// Used only for WRITE_LOCK_NAME in deprecated create=true 
case:
+using System.Runtime.CompilerServices;
 
 namespace Lucene.Net.Store
 {
@@ -462,51 +464,81 @@ namespace Lucene.Net.Store
             get { return chunkSize; }
         }
 
-        /// <summary>
+        ///// <summary>
         /// Writes output with <see cref="FileStream.Write(byte[], int, int)"/>
         /// </summary>
+        // LUCENENET specific: Since FileStream does its own buffering, this 
class was refactored
+        // to do all checksum operations as well as writing to the FileStream. 
By doing this we elminate
+        // the extra set of buffers that were only creating unnecessary memory 
allocations and copy operations.
         protected class FSIndexOutput : BufferedIndexOutput
         {
-            // LUCENENET specific: chunk size not needed
+            private const int CHUNK_SIZE = DEFAULT_BUFFER_SIZE;
 
             private readonly FSDirectory parent;
             internal readonly string name;
             private readonly FileStream file;
             private volatile bool isOpen; // remember if the file is open, so 
that we don't try to close it more than once
+            private readonly CRC32 crc = new CRC32();
 
             public FSIndexOutput(FSDirectory parent, string name)
-                : base(/*CHUNK_SIZE*/)
+                : base(CHUNK_SIZE, null)
             {
                 this.parent = parent;
                 this.name = name;
-                file = new 
FileStream(Path.Combine(parent.m_directory.FullName, name), 
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
+                file = new FileStream(
+                    path: Path.Combine(parent.m_directory.FullName, name),
+                    mode: FileMode.OpenOrCreate,
+                    access: FileAccess.Write,
+                    share: FileShare.ReadWrite,
+                    bufferSize: CHUNK_SIZE);
                 isOpen = true;
             }
 
+            /// <inheritdoc/>
+            public override void WriteByte(byte b)
+            {
+                if (!isOpen)
+                    throw new ObjectDisposedException(nameof(FSIndexOutput));
+
+                crc.Update(b);
+                file.WriteByte(b);
+            }
+
+            /// <inheritdoc/>
+            public override void WriteBytes(byte[] b, int offset, int length)
+            {
+                if (!isOpen)
+                    throw new ObjectDisposedException(nameof(FSIndexOutput));
+
+                crc.Update(b, offset, length);
+                file.Write(b, offset, length);
+            }
+
+            /// <inheritdoc/>
             protected internal override void FlushBuffer(byte[] b, int offset, 
int size)
             {
-                Debug.Assert(isOpen);
+                if (!isOpen)
+                    throw new ObjectDisposedException(nameof(FSIndexOutput));
 
-                // LUCENENET specific: FileStream is already optimized to 
write natively
-                // if over the buffer size that is passed through its 
constructor. So,
-                // all we need to do is Write().
+                crc.Update(b, offset, size);
                 file.Write(b, offset, size);
-
-                //Debug.Assert(size == 0);
             }
 
+            /// <inheritdoc/>
+            [MethodImpl(MethodImplOptions.NoInlining)]
             public override void Flush()
             {
-                base.Flush();
-                // LUCENENET specific - writing bytes into the FileStream (in 
FlushBuffer()) does not immediately
-                // persist them on disk. We need to explicitly call 
FileStream.Flush() to move them there.
+                if (!isOpen)
+                    throw new ObjectDisposedException(nameof(FSIndexOutput));
+
                 file.Flush();
             }
 
+            /// <inheritdoc/>
             protected override void Dispose(bool disposing)
             {
                 if (disposing)
-                { 
+                {
                     parent.OnIndexOutputClosed(this);
                     // only close the file if it has not been closed yet
                     if (isOpen)
@@ -514,7 +546,6 @@ namespace Lucene.Net.Store
                         IOException priorE = null;
                         try
                         {
-                            base.Dispose(disposing); // LUCENENET NOTE: This 
handles Flush() for us automatically, but we need to call Flush(true) to ensure 
everything persists
                             file.Flush(flushToDisk: true);
                         }
                         catch (IOException ioe)
@@ -535,13 +566,25 @@ namespace Lucene.Net.Store
             [Obsolete("(4.1) this method will be removed in Lucene 5.0")]
             public override void Seek(long pos)
             {
-                base.Seek(pos);
+                if (!isOpen)
+                    throw new ObjectDisposedException(nameof(FSIndexOutput));
+
                 file.Seek(pos, SeekOrigin.Begin);
             }
 
+            /// <inheritdoc/>
             public override long Length => file.Length;
 
             // LUCENENET NOTE: FileStream doesn't have a way to set length
+
+            /// <inheritdoc/>
+            public override long Checksum => crc.Value; // LUCENENET specific 
- need to override, since we are buffering locally
+
+            /// <inheritdoc/>
+            public override long GetFilePointer() // LUCENENET specific - need 
to override, since we are buffering locally
+            {
+                return file.Position;
+            }
         }
 
         // LUCENENET specific: Fsync is pointless in .NET, since we are 

Reply via email to