@@ -12,10 +12,10 @@ use tokio::sync::Semaphore;
12
12
use crate :: {
13
13
backoff:: Backoff ,
14
14
pd:: PdClient ,
15
- request:: { KvRequest , Shardable } ,
15
+ request:: { shard :: HasNextBatch , KvRequest , NextBatch , Shardable } ,
16
16
stats:: tikv_stats,
17
17
store:: RegionStore ,
18
- transaction:: { resolve_locks, HasLocks } ,
18
+ transaction:: { resolve_locks, HasLocks , ResolveLocksContext , ResolveLocksOptions } ,
19
19
util:: iter:: FlatMapOkIterExt ,
20
20
Error , Result ,
21
21
} ;
@@ -442,6 +442,169 @@ where
442
442
}
443
443
}
444
444
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
+
445
608
/// When executed, the plan extracts errors from its inner plan, and returns an
446
609
/// `Err` wrapping the error.
447
610
///
0 commit comments