66using System . Collections . Concurrent ;
77using System . IO ;
88using System . IO . MemoryMappedFiles ;
9+ using System . Linq ;
910using System . Runtime . CompilerServices ;
1011using System . Threading ;
1112using SCG = System . Collections . Generic ;
1213
14+ #nullable enable
15+
1316namespace Lucene . Net . Store
1417{
1518 /*
@@ -29,8 +32,6 @@ namespace Lucene.Net.Store
2932 * limitations under the License.
3033 */
3134
32- using Constants = Lucene . Net . Util . Constants ;
33-
3435 /// <summary>
3536 /// File-based <see cref="Directory"/> implementation that uses
3637 /// <see cref="MemoryMappedFile"/> for reading, and
@@ -91,7 +92,7 @@ private readonly ConcurrentDictionary<string, Lazy<SharedMapping>> _mappings
9192 /// <param name="lockFactory"> the lock factory to use, or null for the default
9293 /// (<see cref="NativeFSLockFactory"/>); </param>
9394 /// <exception cref="IOException"> if there is a low-level I/O error </exception>
94- public MMapDirectory ( DirectoryInfo path , LockFactory lockFactory )
95+ public MMapDirectory ( DirectoryInfo path , LockFactory ? lockFactory )
9596 : this ( path , lockFactory , DEFAULT_MAX_BUFF )
9697 {
9798 }
@@ -126,7 +127,7 @@ public MMapDirectory(DirectoryInfo path)
126127 /// <b>Please note:</b> The chunk size is always rounded down to a power of 2.
127128 /// </param>
128129 /// <exception cref="IOException"> if there is a low-level I/O error </exception>
129- public MMapDirectory ( DirectoryInfo path , LockFactory lockFactory , int maxChunkSize )
130+ public MMapDirectory ( DirectoryInfo path , LockFactory ? lockFactory , int maxChunkSize )
130131 : base ( path , lockFactory )
131132 {
132133 if ( maxChunkSize <= 0 )
@@ -146,7 +147,7 @@ public MMapDirectory(DirectoryInfo path, LockFactory lockFactory, int maxChunkSi
146147 /// <param name="lockFactory"> the lock factory to use, or null for the default
147148 /// (<see cref="NativeFSLockFactory"/>); </param>
148149 /// <exception cref="IOException"> if there is a low-level I/O error </exception>
149- public MMapDirectory ( string path , LockFactory lockFactory )
150+ public MMapDirectory ( string path , LockFactory ? lockFactory )
150151 : this ( path , lockFactory , DEFAULT_MAX_BUFF )
151152 {
152153 }
@@ -185,7 +186,7 @@ public MMapDirectory(string path)
185186 /// <b>Please note:</b> The chunk size is always rounded down to a power of 2.
186187 /// </param>
187188 /// <exception cref="IOException"> if there is a low-level I/O error </exception>
188- public MMapDirectory ( string path , LockFactory lockFactory , int maxChunkSize )
189+ public MMapDirectory ( string path , LockFactory ? lockFactory , int maxChunkSize )
189190 : this ( new DirectoryInfo ( path ) , lockFactory , maxChunkSize )
190191 {
191192 }
@@ -296,7 +297,6 @@ public override IndexInputSlicer CreateSlicer(string name, IOContext context)
296297 // refcount reaches zero.
297298 internal void ReleaseMapping ( string file , Lazy < SharedMapping > lazy )
298299 {
299- if ( lazy == null ) return ;
300300 SharedMapping mapping ;
301301 try
302302 {
@@ -351,7 +351,7 @@ private sealed class IndexInputSlicerAnonymousClass : IndexInputSlicer
351351 // issued from it piggyback on that ref (they do not increment).
352352 private readonly Lazy < SharedMapping > mappingLazy ;
353353 private readonly SharedMapping mapping ;
354- private int disposed = 0 ; // LUCENENET specific - allow double-dispose
354+ private int disposed /* = 0 */ ; // LUCENENET specific - allow double-dispose
355355 // Track issued slices so that Dispose cascades. Lucene's
356356 // contract is that after slicer.Dispose, reads from any slice
357357 // (or clone of a slice) throw AlreadyClosedException.
@@ -408,12 +408,13 @@ protected override void Dispose(bool disposing)
408408
409409 if ( disposing )
410410 {
411- MMapIndexInput [ ] toDispose ;
411+ IDisposable [ ] toDispose ;
412412 lock ( issuedSlicesLock )
413413 {
414- toDispose = issuedSlices . ToArray ( ) ;
414+ toDispose = issuedSlices . OfType < IDisposable > ( ) . ToArray ( ) ;
415415 issuedSlices . Clear ( ) ;
416416 }
417+
417418 IOUtils . DisposeWhileHandlingException ( toDispose ) ;
418419
419420 // Release the slicer's refcount on the shared mapping.
@@ -497,7 +498,7 @@ internal sealed unsafe class MMapIndexInput : BufferedIndexInput
497498 private readonly SharedMapping mapping ;
498499 private readonly MMapDirectory directory ;
499500 private readonly string file ;
500- private readonly Lazy < SharedMapping > mappingLazy ;
501+ private readonly Lazy < SharedMapping > ? mappingLazy ;
501502
502503 // The window into the shared mapping that this IndexInput sees.
503504 // For OpenInput this is [0, mapping.Length); for OpenSlice it is
@@ -534,7 +535,7 @@ internal MMapIndexInput(string resourceDescription, MMapDirectory directory, str
534535 /// Slice-bufferSize overload used by <see cref="IndexInputSlicer"/>.
535536 /// </summary>
536537 internal MMapIndexInput ( string resourceDescription , MMapDirectory directory , string file ,
537- Lazy < SharedMapping > mappingLazy , SharedMapping mapping ,
538+ Lazy < SharedMapping > ? mappingLazy , SharedMapping mapping ,
538539 long offset , long length , int bufferSize , int chunkSizePower )
539540 : base ( resourceDescription , bufferSize )
540541 {
@@ -664,16 +665,18 @@ protected override void Dispose(bool disposing)
664665 /// </summary>
665666 internal sealed unsafe class SharedMapping
666667 {
667- private readonly MemoryMappedFile memoryMappedFile ;
668+ /// <summary>
669+ /// The memory-mapped file reference for this mapping.
670+ /// Note that this can be null in the edge case of a zero-length mapping.
671+ /// </summary>
672+ private readonly MemoryMappedFile ? memoryMappedFile ;
668673 private readonly FileStream fileStream ;
669- internal readonly Chunk [ ] Chunks ;
670- internal readonly long Length ;
671674
672675 // 1 for the initial creator (held by AcquireMapping until the
673676 // caller transfers it to the returned IndexInput/Slicer).
674677 private int refCount = 1 ;
675678
676- private SharedMapping ( MemoryMappedFile mmf , FileStream fs , Chunk [ ] chunks , long length )
679+ private SharedMapping ( MemoryMappedFile ? mmf , FileStream fs , Chunk [ ] chunks , long length )
677680 {
678681 this . memoryMappedFile = mmf ;
679682 this . fileStream = fs ;
@@ -688,12 +691,11 @@ internal static SharedMapping Create(string file, int chunkSizePower)
688691 // a 4 KiB buffer that would immediately be discarded.
689692 var fs = new FileStream ( file , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ,
690693 bufferSize : 1 , FileOptions . RandomAccess | FileOptions . Asynchronous ) ;
691- MemoryMappedFile mmf = null ;
692- Chunk [ ] chunks = null ;
693- long length ;
694+ MemoryMappedFile ? mmf = null ;
695+ Chunk [ ] ? chunks = null ;
694696 try
695697 {
696- length = fs . Length ;
698+ long length = fs . Length ;
697699 mmf = CreateMemoryMappedFile ( fs , length ) ;
698700 chunks = MapChunks ( mmf , 0 , length , chunkSizePower ) ;
699701 return new SharedMapping ( mmf , fs , chunks , length ) ;
@@ -702,7 +704,7 @@ internal static SharedMapping Create(string file, int chunkSizePower)
702704 {
703705 DisposeChunks ( chunks ) ;
704706 mmf ? . Dispose ( ) ;
705- try { fs . Dispose ( ) ; } catch { /* never propagate from cleanup */ }
707+ IOUtils . DisposeWhileHandlingException ( fs ) ;
706708 throw ;
707709 }
708710 }
@@ -741,13 +743,16 @@ internal bool Release()
741743 internal void DisposeResources ( )
742744 {
743745 DisposeChunks ( Chunks ) ;
744- try { memoryMappedFile ? . Dispose ( ) ; } catch { /* never propagate from cleanup */ }
745- try { fileStream ? . Dispose ( ) ; } catch { /* never propagate from cleanup */ }
746+ IOUtils . DisposeWhileHandlingException ( memoryMappedFile , fileStream ) ;
746747 }
747748
748- private static MemoryMappedFile CreateMemoryMappedFile ( FileStream fc , long requiredCapacity )
749+ internal Chunk [ ] Chunks { get ; }
750+
751+ internal long Length { get ; }
752+
753+ private static MemoryMappedFile ? CreateMemoryMappedFile ( FileStream fc , long requiredCapacity )
749754 {
750- if ( requiredCapacity = = 0 )
755+ if ( requiredCapacity < = 0 )
751756 {
752757 return null ;
753758 }
@@ -780,24 +785,24 @@ private static MemoryMappedFile CreateMemoryMappedFile(FileStream fc, long requi
780785 int prior ;
781786 do
782787 {
783- prior = Volatile . Read ( ref MMapDirectory . s_maxCapacityAttemptsObserved ) ;
788+ prior = Volatile . Read ( ref s_maxCapacityAttemptsObserved ) ;
784789 if ( attemptsTaken <= prior ) break ;
785- } while ( Interlocked . CompareExchange ( ref MMapDirectory . s_maxCapacityAttemptsObserved , attemptsTaken , prior ) != prior ) ;
790+ } while ( Interlocked . CompareExchange ( ref s_maxCapacityAttemptsObserved , attemptsTaken , prior ) != prior ) ;
786791 return mmf ;
787792 }
788793 catch ( ArgumentOutOfRangeException e ) when ( e . ParamName == "capacity" && attempt < maxAttempts - 1 )
789794 {
790- Interlocked . Increment ( ref MMapDirectory . s_capacityRetryCount ) ;
795+ Interlocked . Increment ( ref s_capacityRetryCount ) ;
791796 capacity = Math . Max ( capacity , fc . Length ) ;
792797 attempt ++ ;
793798 }
794799 }
795800 // LUCENENET specific END
796801 }
797802
798- private static Chunk [ ] MapChunks ( MemoryMappedFile mmf , long offset , long length , int chunkSizePower )
803+ private static Chunk [ ] MapChunks ( MemoryMappedFile ? mmf , long offset , long length , int chunkSizePower )
799804 {
800- if ( length == 0 )
805+ if ( length == 0 || mmf == null )
801806 {
802807 return Array . Empty < Chunk > ( ) ;
803808 }
@@ -838,12 +843,19 @@ private static Chunk[] MapChunks(MemoryMappedFile mmf, long offset, long length,
838843 }
839844 }
840845
841- private static void DisposeChunks ( Chunk [ ] chunks )
846+ private static void DisposeChunks ( Chunk [ ] ? chunks )
842847 {
843848 if ( chunks == null ) return ;
844849 foreach ( var c in chunks )
845850 {
846- try { c ? . Close ( ) ; } catch { /* never propagate from cleanup */ }
851+ try
852+ {
853+ c . Close ( ) ;
854+ }
855+ catch
856+ {
857+ /* never propagate from cleanup */
858+ }
847859 }
848860 }
849861 }
@@ -856,7 +868,7 @@ private static void DisposeChunks(Chunk[] chunks)
856868 /// </summary>
857869 internal sealed unsafe class Chunk
858870 {
859- private MemoryMappedViewAccessor accessor ;
871+ private MemoryMappedViewAccessor ? accessor ;
860872 internal readonly long length ;
861873 internal readonly byte * basePtr ;
862874 private int closed ;
0 commit comments