@@ -64,45 +64,25 @@ public void Dispose()
6464
6565 public async IAsyncEnumerable < string > LoadAsync ( )
6666 {
67- // Copy to a temp file under the lock so writers are blocked only briefly
68- string tempPath = Path . GetTempFileName ( ) ;
69-
70- try
67+ // Read directly from the source file. Writers use File.AppendText which opens with
68+ // FileShare.Read, allowing concurrent readers. We open with FileShare.ReadWrite to
69+ // allow concurrent writers. This avoids the overhead of copying to a temp file and
70+ // eliminates lock contention between readers and writers.
71+ var options = new FileStreamOptions
7172 {
72- await s_loggingFileLock . WaitAsync ( ) ;
73-
74- try
75- {
76- // Use FileStream copy instead of File.Copy to avoid copying encryption attributes
77- // which can fail if source is encrypted but temp folder doesn't support encryption
78- await using var sourceStream = new FileStream ( _fileLocationOptions . LoggingPath , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) ;
79- await using var destStream = new FileStream ( tempPath , FileMode . Create , FileAccess . Write , FileShare . None ) ;
80- await sourceStream . CopyToAsync ( destStream ) ;
81- }
82- finally
83- {
84- s_loggingFileLock . Release ( ) ;
85- }
86-
87- // Stream lines from the snapshot so memory stays bounded and writers aren't blocked
88- await using var stream = new FileStream ( tempPath , FileMode . Open , FileAccess . Read , FileShare . Read , bufferSize : 4096 , useAsync : true ) ;
89- using var reader = new StreamReader ( stream ) ;
90-
91- while ( await reader . ReadLineAsync ( ) is { } line )
92- {
93- yield return line ;
94- }
95- }
96- finally
73+ Mode = FileMode . Open ,
74+ Access = FileAccess . Read ,
75+ Share = FileShare . ReadWrite ,
76+ Options = FileOptions . Asynchronous | FileOptions . SequentialScan ,
77+ BufferSize = 4096
78+ } ;
79+
80+ await using var stream = new FileStream ( _fileLocationOptions . LoggingPath , options ) ;
81+ using var reader = new StreamReader ( stream ) ;
82+
83+ while ( await reader . ReadLineAsync ( ) is { } line )
9784 {
98- try
99- {
100- File . Delete ( tempPath ) ;
101- }
102- catch
103- {
104- // Best effort cleanup
105- }
85+ yield return line ;
10686 }
10787 }
10888
0 commit comments