1- use std:: { fmt, io} ;
1+ use std:: {
2+ fmt,
3+ io:: { self , Seek } ,
4+ } ;
25
36use log:: { debug, warn} ;
47
@@ -52,8 +55,14 @@ pub trait SegmentLen: io::Seek {
5255 }
5356}
5457
55- pub trait SegmentReader : io:: BufRead + SegmentLen + Send + Sync { }
56- impl < T : io:: BufRead + SegmentLen + Send + Sync > SegmentReader for T { }
58+ pub trait SegmentReader : io:: BufRead + SegmentLen + Send + Sync {
59+ /// Whether the segment is considered immutable.
60+ ///
61+ /// Currently, this is true when the segment is compressed.
62+ /// [resume_segment_writer] uses this method to indicate that a new segment
63+ /// should be created when opening a commitlog.
64+ fn sealed ( & self ) -> bool ;
65+ }
5766
5867pub trait SegmentWriter : FileLike + io:: Read + io:: Write + SegmentLen + Send + Sync { }
5968impl < T : FileLike + io:: Read + io:: Write + SegmentLen + Send + Sync > SegmentWriter for T { }
@@ -243,21 +252,9 @@ pub fn resume_segment_writer<R: Repo>(
243252 opts : Options ,
244253 offset : u64 ,
245254) -> io:: Result < Result < Writer < R :: SegmentWriter > , Metadata > > {
246- let mut storage = repo. open_segment_writer ( offset) ?;
247- // Ensure we have enough space for this segment.
248- // The segment could have been created without the `fallocate` feature
249- // enabled, so we call this here again to ensure writes can't fail due to
250- // ENOSPC.
251- fallocate ( & mut storage, & opts) ?;
255+ let mut reader = repo. open_segment_reader ( offset) ?;
252256 let offset_index = repo. get_offset_index ( offset) . ok ( ) ;
253- let Metadata {
254- header,
255- tx_range,
256- size_in_bytes,
257- max_epoch,
258- max_commit_offset : _,
259- max_commit : _,
260- } = match Metadata :: extract ( offset, & mut storage, offset_index. as_ref ( ) ) {
257+ let meta = match Metadata :: extract ( offset, & mut reader, offset_index. as_ref ( ) ) {
261258 Err ( error:: SegmentMetadata :: InvalidCommit { sofar, source } ) => {
262259 warn ! ( "invalid commit in segment {offset}: {source}" ) ;
263260 debug ! ( "sofar={sofar:?}" ) ;
@@ -266,34 +263,55 @@ pub fn resume_segment_writer<R: Repo>(
266263 Err ( error:: SegmentMetadata :: Io ( e) ) => return Err ( e) ,
267264 Ok ( meta) => meta,
268265 } ;
269- header
266+ meta . header
270267 . ensure_compatible ( opts. log_format_version , Commit :: CHECKSUM_ALGORITHM )
271268 . map_err ( |msg| io:: Error :: new ( io:: ErrorKind :: InvalidData , msg) ) ?;
272269 // When resuming, the log format version must be equal.
273- if header. log_format_version != opts. log_format_version {
270+ if meta . header . log_format_version != opts. log_format_version {
274271 return Err ( io:: Error :: new (
275272 io:: ErrorKind :: InvalidData ,
276273 format ! (
277274 "log format version mismatch: current={} segment={}" ,
278- opts. log_format_version, header. log_format_version
275+ opts. log_format_version, meta . header. log_format_version
279276 ) ,
280277 ) ) ;
281278 }
282279
283- Ok ( Ok ( Writer {
284- commit : Commit {
285- min_tx_offset : tx_range. end ,
286- n : 0 ,
287- records : Vec :: new ( ) ,
288- epoch : max_epoch,
289- } ,
290- inner : io:: BufWriter :: new ( storage) ,
291-
292- min_tx_offset : tx_range. start ,
293- bytes_written : size_in_bytes,
294-
295- offset_index_head : create_offset_index_writer ( repo, offset, opts) ,
296- } ) )
280+ if reader. sealed ( ) {
281+ Ok ( Err ( meta) )
282+ } else {
283+ let Metadata {
284+ header : _,
285+ tx_range,
286+ size_in_bytes,
287+ max_epoch,
288+ max_commit_offset : _,
289+ max_commit : _,
290+ } = meta;
291+ let mut writer = repo. open_segment_writer ( offset) ?;
292+ // Ensure we have enough space for this segment.
293+ // The segment could have been created without the `fallocate` feature
294+ // enabled, so we call this here again to ensure writes can't fail due
295+ // to ENOSPC.
296+ fallocate ( & mut writer, & opts) ?;
297+ // We use `O_APPEND`, but make the file offset consistent regardless.
298+ writer. seek ( io:: SeekFrom :: End ( 0 ) ) ?;
299+
300+ Ok ( Ok ( Writer {
301+ commit : Commit {
302+ min_tx_offset : tx_range. end ,
303+ n : 0 ,
304+ records : Vec :: new ( ) ,
305+ epoch : max_epoch,
306+ } ,
307+ inner : io:: BufWriter :: new ( writer) ,
308+
309+ min_tx_offset : tx_range. start ,
310+ bytes_written : size_in_bytes,
311+
312+ offset_index_head : create_offset_index_writer ( repo, offset, opts) ,
313+ } ) )
314+ }
297315}
298316
299317/// Open the existing segment at `offset` for reading.
0 commit comments