@@ -27,16 +27,16 @@ namespace SeqCli.Forwarder.Storage;
2727sealed class BufferReader
2828{
2929 readonly StoreDirectory _storeDirectory ;
30- BufferReaderHead ? _discardingHead ;
31- BufferReaderHead ? _readHead ;
30+ BufferPosition ? _discardingHead ;
31+ BufferPosition _readHead ;
3232 List < BufferReaderChunk > _sortedChunks ;
3333
3434 BufferReader ( StoreDirectory storeDirectory )
3535 {
36- _sortedChunks = new List < BufferReaderChunk > ( ) ;
36+ _sortedChunks = [ ] ;
3737 _storeDirectory = storeDirectory ;
3838 _discardingHead = null ;
39- _readHead = null ;
39+ _readHead = new ( 0 , 0 ) ;
4040 }
4141
4242 public static BufferReader Open ( StoreDirectory storeDirectory )
@@ -86,19 +86,19 @@ from the underlying chunks.
8686
8787 // If the chunk has changed (it may have been deleted externally)
8888 // then stop discarding
89- if ( chunk . Name . Id != _discardingHead . Value . Chunk )
89+ if ( chunk . Name . Id != _discardingHead . Value . ChunkId )
9090 {
9191 _discardingHead = null ;
9292
9393 ArrayPool < byte > . Shared . Return ( discardingRentedArray ) ;
9494 break ;
9595 }
9696
97- var chunkHead = Head ( chunk ) ;
97+ var chunkHead = Extents ( chunk ) ;
9898
9999 // Attempt to fill the buffer with data from the underlying chunk
100100 if ( ! TryFillChunk ( chunk ,
101- chunkHead with { CommitHead = _discardingHead . Value . CommitHead } ,
101+ chunkHead with { CommitHead = _discardingHead . Value . Offset } ,
102102 discardingBatchBuffer ,
103103 out var fill ) )
104104 {
@@ -119,11 +119,11 @@ from the underlying chunks.
119119
120120 _discardingHead = _discardingHead . Value with
121121 {
122- CommitHead = _discardingHead . Value . CommitHead + fill . Value
122+ Offset = _discardingHead . Value . Offset + fill . Value
123123 } ;
124- _readHead = _discardingHead ;
124+ _readHead = _discardingHead . Value ;
125125
126- var isChunkFinished = _discardingHead . Value . CommitHead == chunkHead . WriteHead ;
126+ var isChunkFinished = _discardingHead . Value . Offset == chunkHead . WriteHead ;
127127
128128 // If the chunk is finished or a newline is found then stop discarding
129129 if ( firstNewlineIndex >= 0 || ( isChunkFinished && _sortedChunks . Count > 1 ) )
@@ -153,15 +153,15 @@ from the underlying chunks.
153153 var batchBuffer = rentedArray . AsSpan ( ) [ ..maxSize ] ;
154154 var batchLength = 0 ;
155155
156- BufferReaderHead ? batchHead = null ;
156+ BufferPosition ? batchHead = null ;
157157 var chunkIndex = 0 ;
158158
159159 // Try fill the buffer with as much data as possible
160160 // by walking over all chunks
161161 while ( chunkIndex < _sortedChunks . Count )
162162 {
163163 var chunk = _sortedChunks [ chunkIndex ] ;
164- var chunkHead = Head ( chunk ) ;
164+ var chunkHead = Extents ( chunk ) ;
165165
166166 if ( ! TryFillChunk ( chunk , chunkHead , batchBuffer [ batchLength ..] , out var fill ) )
167167 {
@@ -192,7 +192,7 @@ from the underlying chunks.
192192 // If this is the first chunk then we've hit an oversize payload
193193 if ( chunkIndex == 0 )
194194 {
195- _discardingHead = new BufferReaderHead ( chunk . Name . Id , chunkHead . CommitHead + fill . Value ) ;
195+ _discardingHead = new BufferPosition ( chunk . Name . Id , chunkHead . CommitHead + fill . Value ) ;
196196
197197 // Ensures we don't attempt to yield the data we've read
198198 batchHead = null ;
@@ -206,7 +206,7 @@ from the underlying chunks.
206206 }
207207
208208 batchLength += fill . Value ;
209- batchHead = new BufferReaderHead ( chunk . Name . Id , chunkHead . CommitHead + fill . Value ) ;
209+ batchHead = new BufferPosition ( chunk . Name . Id , chunkHead . CommitHead + fill . Value ) ;
210210
211211 chunkIndex += 1 ;
212212 }
@@ -233,19 +233,26 @@ from the underlying chunks.
233233 /// This method does not throw.
234234 /// </summary>
235235 /// <param name="newReaderHead">The new head to resume reading from.</param>
236- public void AdvanceTo ( BufferReaderHead newReaderHead )
236+ public void AdvanceTo ( BufferPosition newReaderHead )
237237 {
238238 var removeLength = 0 ;
239+
239240 foreach ( var chunk in _sortedChunks )
240241 {
241242 // A portion of the chunk is being skipped
242- if ( chunk . Name . Id == newReaderHead . Chunk ) break ;
243+ if ( chunk . Name . Id == newReaderHead . ChunkId ) break ;
243244
244245 // The remainder of the chunk is being skipped
245- if ( chunk . Name . Id < newReaderHead . Chunk )
246+ if ( chunk . Name . Id < newReaderHead . ChunkId )
247+ {
246248 _storeDirectory . TryDelete ( chunk . Name . ToString ( ) ) ;
249+ }
247250 else
248- throw new Exception ( "Chunks are out of order." ) ;
251+ {
252+ // We might end up here if a chunk in the middle of the range was
253+ // deleted from disk, while a saved bookmark references that chunk.
254+ break ;
255+ }
249256
250257 removeLength += 1 ;
251258 }
@@ -254,29 +261,27 @@ public void AdvanceTo(BufferReaderHead newReaderHead)
254261 _sortedChunks . RemoveRange ( 0 , removeLength ) ;
255262 }
256263
257- BufferReaderChunkHead Head ( BufferReaderChunk chunk )
264+ BufferReaderChunkExtents Extents ( BufferReaderChunk chunk )
258265 {
259- if ( _readHead != null && chunk . Name . Id == _readHead . Value . Chunk )
266+ if ( chunk . Name . Id == _readHead . ChunkId )
260267 return chunk . Chunk . TryGetLength ( out var writeHead )
261- ? new BufferReaderChunkHead ( Math . Min ( _readHead . Value . CommitHead , writeHead . Value ) , writeHead . Value )
262- : new BufferReaderChunkHead ( _readHead . Value . CommitHead , _readHead . Value . CommitHead ) ;
268+ ? new BufferReaderChunkExtents ( Math . Min ( _readHead . Offset , writeHead . Value ) , writeHead . Value )
269+ : new BufferReaderChunkExtents ( _readHead . Offset , _readHead . Offset ) ;
263270
264271 chunk . Chunk . TryGetLength ( out var length ) ;
265- return new BufferReaderChunkHead ( 0 , length ?? 0 ) ;
272+ return new BufferReaderChunkExtents ( 0 , length ?? 0 ) ;
266273 }
267274
268275 void ReadChunks ( )
269276 {
270- var head = _readHead ?? new BufferReaderHead ( 0 , 0 ) ;
271-
272- List < BufferReaderChunk > chunks = new ( ) ;
277+ List < BufferReaderChunk > chunks = [ ] ;
273278
274279 foreach ( var ( fileName , file ) in _storeDirectory
275280 . List ( candidateName => Path . GetExtension ( candidateName ) is ".clef" ) )
276281 {
277282 if ( ! ChunkName . TryParse ( fileName , out var parsedChunkName ) ) continue ;
278283
279- if ( parsedChunkName . Value . Id >= head . Chunk )
284+ if ( parsedChunkName . Value . Id >= _readHead . ChunkId )
280285 chunks . Add ( new BufferReaderChunk ( parsedChunkName . Value , file ) ) ;
281286 else
282287 // If the chunk is before the one we're expecting to read then delete it; we've already processed it
@@ -299,15 +304,15 @@ void ReadChunks()
299304 }
300305 }
301306
302- static bool TryFillChunk ( BufferReaderChunk chunk , BufferReaderChunkHead chunkHead , Span < byte > buffer ,
307+ static bool TryFillChunk ( BufferReaderChunk chunk , BufferReaderChunkExtents chunkExtents , Span < byte > buffer ,
303308 [ NotNullWhen ( true ) ] out int ? filled )
304309 {
305310 var remaining = buffer . Length ;
306- var fill = ( int ) Math . Min ( remaining , chunkHead . Unadvanced ) ;
311+ var fill = ( int ) Math . Min ( remaining , chunkExtents . Unadvanced ) ;
307312
308313 try
309314 {
310- if ( ! chunk . TryCopyTo ( buffer , chunkHead , fill ) )
315+ if ( ! chunk . TryCopyTo ( buffer , chunkExtents , fill ) )
311316 {
312317 filled = null ;
313318 return false ;
0 commit comments