@@ -12,10 +12,10 @@ use tokio::sync::Semaphore;
1212use crate :: {
1313 backoff:: Backoff ,
1414 pd:: PdClient ,
15- request:: { KvRequest , Shardable } ,
15+ request:: { shard :: HasNextBatch , KvRequest , NextBatch , Shardable } ,
1616 stats:: tikv_stats,
1717 store:: RegionStore ,
18- transaction:: { resolve_locks, HasLocks } ,
18+ transaction:: { resolve_locks, HasLocks , ResolveLocksContext , ResolveLocksOptions } ,
1919 util:: iter:: FlatMapOkIterExt ,
2020 Error , Result ,
2121} ;
@@ -442,6 +442,169 @@ where
442442 }
443443}
444444
445+ #[ derive( Default ) ]
446+ pub struct CleanupLocksResult {
447+ pub region_error : Option < errorpb:: Error > ,
448+ pub key_error : Option < Vec < Error > > ,
449+ pub meet_locks : usize ,
450+ // TODO: pub resolved_locks: usize,
451+ }
452+
453+ impl Clone for CleanupLocksResult {
454+ fn clone ( & self ) -> Self {
455+ Self {
456+ meet_locks : self . meet_locks ,
457+ ..Default :: default ( ) // Ignore errors, which should be extracted by `extract_error()`.
458+ }
459+ }
460+ }
461+
462+ impl HasRegionError for CleanupLocksResult {
463+ fn region_error ( & mut self ) -> Option < errorpb:: Error > {
464+ self . region_error . take ( )
465+ }
466+ }
467+
468+ impl HasKeyErrors for CleanupLocksResult {
469+ fn key_errors ( & mut self ) -> Option < Vec < Error > > {
470+ self . key_error . take ( )
471+ }
472+ }
473+
474+ impl Merge < CleanupLocksResult > for Collect {
475+ type Out = CleanupLocksResult ;
476+
477+ fn merge ( & self , input : Vec < Result < CleanupLocksResult > > ) -> Result < Self :: Out > {
478+ input
479+ . into_iter ( )
480+ . fold ( Ok ( CleanupLocksResult :: default ( ) ) , |acc, x| {
481+ Ok ( CleanupLocksResult {
482+ meet_locks : acc. unwrap ( ) . meet_locks + x?. meet_locks ,
483+ ..Default :: default ( )
484+ } )
485+ } )
486+ }
487+ }
488+
489+ pub struct CleanupLocks < P : Plan , PdC : PdClient > {
490+ pub logger : slog:: Logger ,
491+ pub inner : P ,
492+ pub ctx : ResolveLocksContext ,
493+ pub options : ResolveLocksOptions ,
494+ pub store : Option < RegionStore > ,
495+ pub pd_client : Arc < PdC > ,
496+ pub backoff : Backoff ,
497+ }
498+
499+ impl < P : Plan , PdC : PdClient > Clone for CleanupLocks < P , PdC > {
500+ fn clone ( & self ) -> Self {
501+ CleanupLocks {
502+ logger : self . logger . clone ( ) ,
503+ inner : self . inner . clone ( ) ,
504+ ctx : self . ctx . clone ( ) ,
505+ options : self . options ,
506+ store : None ,
507+ pd_client : self . pd_client . clone ( ) ,
508+ backoff : self . backoff . clone ( ) ,
509+ }
510+ }
511+ }
512+
513+ #[ async_trait]
514+ impl < P : Plan + Shardable + NextBatch , PdC : PdClient > Plan for CleanupLocks < P , PdC >
515+ where
516+ P :: Result : HasLocks + HasNextBatch + HasKeyErrors + HasRegionError ,
517+ {
518+ type Result = CleanupLocksResult ;
519+
520+ async fn execute ( & self ) -> Result < Self :: Result > {
521+ let mut result = CleanupLocksResult :: default ( ) ;
522+ let mut inner = self . inner . clone ( ) ;
523+ let mut lock_resolver =
524+ crate :: transaction:: LockResolver :: new ( self . logger . clone ( ) , self . ctx . clone ( ) ) ;
525+ let region = & self . store . as_ref ( ) . unwrap ( ) . region_with_leader ;
526+ let mut has_more_batch = true ;
527+
528+ while has_more_batch {
529+ let mut scan_lock_resp = inner. execute ( ) . await ?;
530+
531+ // Propagate errors to `retry_multi_region` for retry.
532+ if let Some ( e) = scan_lock_resp. key_errors ( ) {
533+ info ! (
534+ self . logger,
535+ "CleanupLocks::execute, inner key errors:{:?}" , e
536+ ) ;
537+ result. key_error = Some ( e) ;
538+ return Ok ( result) ;
539+ } else if let Some ( e) = scan_lock_resp. region_error ( ) {
540+ info ! (
541+ self . logger,
542+ "CleanupLocks::execute, inner region error:{}" ,
543+ e. get_message( )
544+ ) ;
545+ result. region_error = Some ( e) ;
546+ return Ok ( result) ;
547+ }
548+
549+ // Iterate to next batch of inner.
550+ match scan_lock_resp. has_next_batch ( ) {
551+ Some ( range) if region. contains ( range. 0 . as_ref ( ) ) => {
552+ debug ! ( self . logger, "CleanupLocks::execute, next range:{:?}" , range) ;
553+ inner. next_batch ( range) ;
554+ }
555+ _ => has_more_batch = false ,
556+ }
557+
558+ let mut locks = scan_lock_resp. take_locks ( ) ;
559+ if locks. is_empty ( ) {
560+ break ;
561+ }
562+ if locks. len ( ) < self . options . batch_size as usize {
563+ has_more_batch = false ;
564+ }
565+
566+ if self . options . async_commit_only {
567+ locks = locks
568+ . into_iter ( )
569+ . filter ( |l| l. get_use_async_commit ( ) )
570+ . collect :: < Vec < _ > > ( ) ;
571+ }
572+ debug ! (
573+ self . logger,
574+ "CleanupLocks::execute, meet locks:{}" ,
575+ locks. len( )
576+ ) ;
577+ result. meet_locks += locks. len ( ) ;
578+
579+ match lock_resolver
580+ . cleanup_locks ( self . store . clone ( ) . unwrap ( ) , locks, self . pd_client . clone ( ) )
581+ . await
582+ {
583+ Ok ( ( ) ) => { }
584+ Err ( Error :: ExtractedErrors ( mut errors) ) => {
585+ // Propagate errors to `retry_multi_region` for retry.
586+ if let Error :: RegionError ( e) = errors. pop ( ) . unwrap ( ) {
587+ result. region_error = Some ( * e) ;
588+ } else {
589+ result. key_error = Some ( errors) ;
590+ }
591+ return Ok ( result) ;
592+ }
593+ Err ( e) => {
594+ return Err ( e) ;
595+ }
596+ }
597+
598+ // TODO: improve backoff
599+ // if self.backoff.is_none() {
600+ // return Err(Error::ResolveLockError);
601+ // }
602+ }
603+
604+ Ok ( result)
605+ }
606+ }
607+
445608/// When executed, the plan extracts errors from its inner plan, and returns an
446609/// `Err` wrapping the error.
447610///
0 commit comments