@@ -88,6 +88,8 @@ pub trait Queue<V>: Send
8888where
8989 V : InternalMessageValue + Send + Sync ,
9090{
91+ fn zerostate_id ( & self ) -> ZerostateId ;
92+
9193 /// Create iterator for specified shard and return it
9294 fn iterator (
9395 & self ,
@@ -124,13 +126,16 @@ where
124126 partitions : & FastHashSet < QueuePartitionIdx > ,
125127 ) -> Result < ( ) > ;
126128
127- /// Roll back commit pointers to the specified top blocks .
129+ /// Roll back commit pointers to the specified ones .
128130 fn rollback_commit_pointers (
129131 & self ,
130132 to_mc_block_id : & BlockId ,
131- to_top_blocks : & [ TopBlockIdUpdated ] ,
133+ to_commit_pointers : FastHashMap < ShardIdent , ( Option < QueueKey > , u32 ) > ,
132134 ) -> Result < Vec < ShardIdent > > ;
133135
136+ /// Clear commit pointers and last committed mc block id.
137+ fn clear_commit_pointers ( & self ) -> Result < Vec < ShardIdent > > ;
138+
134139 /// Remove all data in uncommitted zone
135140 fn clear_uncommitted_state (
136141 & self ,
@@ -208,6 +213,10 @@ where
208213 P : QueueState < V > + Send + Sync + ' static ,
209214 V : InternalMessageValue + Send + Sync ,
210215{
216+ fn zerostate_id ( & self ) -> ZerostateId {
217+ self . zerostate_id
218+ }
219+
211220 fn iterator (
212221 & self ,
213222 partition : QueuePartitionIdx ,
@@ -443,97 +452,44 @@ where
443452
444453 fn rollback_commit_pointers (
445454 & self ,
446- to_mc_block_id : & BlockId ,
447- to_top_blocks : & [ TopBlockIdUpdated ] ,
455+ mc_block_id : & BlockId ,
456+ to_commit_pointers : FastHashMap < ShardIdent , ( Option < QueueKey > , u32 ) > ,
448457 ) -> Result < Vec < ShardIdent > > {
449458 let _global_write_guard = self . global_lock . write ( ) ;
450459
451460 let old_commit_pointers = self . state . get_commit_pointers ( ) ?;
452- let mut new_commit_pointers = FastHashMap :: default ( ) ;
453- let mut clear_commit_state = false ;
454-
455- for item in to_top_blocks {
456- let block_id = & item. block . block_id ;
457-
458- let diff = self
459- . state
460- . get_diff_info ( & block_id. shard , block_id. seqno , DiffZone :: Both ) ?;
461461
462- let diff = match diff {
463- None if item. updated && item. block . ref_by_mc_seqno > self . zerostate_id . seqno => {
464- // SAFETY: In this recovery fallback, a missing updated target diff is treated as
465- // an already GC-collected queue boundary. Since the target MC commit may not be
466- // idempotently committable without its diff info, the whole queue commit state is
467- // reset and the following clear_uncommitted_state call removes the remaining tails.
468- tracing:: warn!(
469- target: tracing_targets:: MQ ,
470- "Clearing all commit pointers after missing updated shard {} with mc ref {} (zerostate {}) \
471- during rollback to seqno {}: target diff is missing and old commit pointers: {:?}",
472- block_id. shard,
473- item. block. ref_by_mc_seqno,
474- self . zerostate_id. seqno,
475- block_id. seqno,
476- old_commit_pointers,
477- ) ;
478- clear_commit_state = true ;
479- break ;
462+ // build new commit pointers
463+ let mut new_commit_pointers = FastHashMap :: default ( ) ;
464+ for ( shard_id, ( max_message, seqno) ) in to_commit_pointers {
465+ if let Some ( max_message) = max_message {
466+ if new_commit_pointers
467+ . insert ( shard_id, ( max_message, seqno) )
468+ . is_some ( )
469+ {
470+ bail ! ( "Duplicate shard in rollback_commit_pointers: {}" , shard_id) ;
480471 }
481- None if !item. updated => {
482- if let Some ( old_pointer) = old_commit_pointers. get ( & block_id. shard ) {
483- if old_pointer. seqno != block_id. seqno {
484- // SAFETY: In this recovery fallback, a missing target diff is treated as an
485- // already GC-collected queue boundary. Dropping this shard pointer lets the
486- // following clear_uncommitted_state call remove the remaining ahead-of-applied
487- // queue suffix for this shard.
488- tracing:: warn!(
489- target: tracing_targets:: MQ ,
490- "Dropping commit pointer for unchanged shard {} during rollback to seqno {}: \
491- target diff is missing and old pointer seqno is {}",
492- block_id. shard,
493- block_id. seqno,
494- old_pointer. seqno,
495- ) ;
496- continue ;
497- }
498- if new_commit_pointers
499- . insert ( block_id. shard , ( old_pointer. queue_key , old_pointer. seqno ) )
500- . is_some ( )
501- {
502- bail ! (
503- "Duplicate shard in rollback_commit_pointers: {}" ,
504- block_id. shard
505- ) ;
506- }
472+ } else {
473+ // check if missed mandatory commit pointers in rollback
474+ if let Some ( old_pointer) = old_commit_pointers. get ( & shard_id) {
475+ if old_pointer. seqno != seqno {
476+ bail ! (
477+ "Cannot roll back commit pointer for shard {} on seqno {}: diff is missing" ,
478+ shard_id,
479+ seqno,
480+ ) ;
481+ }
482+ if new_commit_pointers
483+ . insert ( shard_id, ( old_pointer. queue_key , old_pointer. seqno ) )
484+ . is_some ( )
485+ {
486+ bail ! ( "Duplicate shard in rollback_commit_pointers: {}" , shard_id) ;
507487 }
508- continue ;
509488 }
510- None => continue ,
511- Some ( diff) => diff,
512- } ;
513-
514- if new_commit_pointers
515- . insert ( block_id. shard , ( diff. max_message , diff. seqno ) )
516- . is_some ( )
517- {
518- bail ! (
519- "Duplicate shard in rollback_commit_pointers: {}" ,
520- block_id. shard
521- ) ;
522489 }
523490 }
524491
525- // fully clear commit state when unable to rollback
526- if clear_commit_state {
527- let removed_commit_pointer_shards: Vec < _ > =
528- old_commit_pointers. keys ( ) . copied ( ) . collect ( ) ;
529- tracing:: debug!( target: tracing_targets:: MQ ,
530- ?removed_commit_pointer_shards,
531- "rollback_commit_pointers: clear_commit_pointers" ,
532- ) ;
533- self . state . clear_commit_pointers ( ) ?;
534- return Ok ( removed_commit_pointer_shards) ;
535- }
536-
492+ // detect commit pointers that will be removed
537493 let removed_commit_pointer_shards: Vec < _ > = old_commit_pointers
538494 . keys ( )
539495 . filter ( |shard_id| !new_commit_pointers. contains_key ( shard_id) )
@@ -543,11 +499,22 @@ where
543499 tracing:: debug!( target: tracing_targets:: MQ ,
544500 ?new_commit_pointers,
545501 ?removed_commit_pointer_shards,
546- "rollback_commit_pointers" ,
502+ "rollback_commit_pointers: replace_commit_pointers " ,
547503 ) ;
548504
549505 self . state
550- . replace_commit_pointers ( new_commit_pointers, to_mc_block_id) ?;
506+ . replace_commit_pointers ( new_commit_pointers, mc_block_id) ?;
507+
508+ Ok ( removed_commit_pointer_shards)
509+ }
510+
511+ fn clear_commit_pointers ( & self ) -> Result < Vec < ShardIdent > > {
512+ let _global_write_guard = self . global_lock . write ( ) ;
513+
514+ let old_commit_pointers = self . state . get_commit_pointers ( ) ?;
515+ let removed_commit_pointer_shards: Vec < _ > = old_commit_pointers. keys ( ) . copied ( ) . collect ( ) ;
516+
517+ self . state . clear_commit_pointers ( ) ?;
551518
552519 Ok ( removed_commit_pointer_shards)
553520 }
0 commit comments