@@ -6,6 +6,7 @@ use std::{
66 Arc , Mutex ,
77 atomic:: { AtomicUsize , Ordering } ,
88 } ,
9+ time:: Instant ,
910} ;
1011
1112use async_recursion:: async_recursion;
@@ -47,6 +48,7 @@ pub struct ImportRepo {
4748 pub command_list : Mutex < Vec < RefCommand > > ,
4849 pub unpack_redlock : Arc < RedLock > ,
4950 pub git_object_cache : Arc < GitObjectCache > ,
51+ pub receive_pack_extra_timings_ms : Mutex < Vec < ( String , u128 ) > > ,
5052}
5153
5254#[ async_trait]
@@ -55,6 +57,19 @@ impl RepoHandler for ImportRepo {
5557 false
5658 }
5759
60+ fn save_entry_concurrency ( & self ) -> usize {
61+ self . storage . config ( ) . pack . save_entry_concurrency
62+ }
63+
64+ fn receive_pack_extra_timings_ms ( & self ) -> Vec < ( String , u128 ) > {
65+ std:: mem:: take (
66+ & mut self
67+ . receive_pack_extra_timings_ms
68+ . lock ( )
69+ . expect ( "receive_pack_extra_timings_ms lock poisoned" ) ,
70+ )
71+ }
72+
5873 fn sync_commands_after_unpack ( & self , commands : & [ RefCommand ] ) {
5974 * self
6075 . command_list
@@ -75,10 +90,32 @@ impl RepoHandler for ImportRepo {
7590 }
7691
7792 async fn finalize_receive_pack ( & self ) -> Result < ( ) , MegaError > {
78- let guard = self . unpack_redlock . clone ( ) . lock ( ) . await ?;
93+ let t0 = Instant :: now ( ) ;
94+ let t_fp = Instant :: now ( ) ;
7995 self . traverses_tree_and_update_filepath ( ) . await ?;
96+ self . receive_pack_extra_timings_ms
97+ . lock ( )
98+ . expect ( "receive_pack_extra_timings_ms lock poisoned" )
99+ . push ( (
100+ "import_filepath_update_ms" . to_string ( ) ,
101+ t_fp. elapsed ( ) . as_millis ( ) ,
102+ ) ) ;
103+
104+ let t_attach = Instant :: now ( ) ;
80105 self . attach_to_monorepo_parent ( ) . await ?;
81- guard. unlock ( ) . await ?;
106+ self . receive_pack_extra_timings_ms
107+ . lock ( )
108+ . expect ( "receive_pack_extra_timings_ms lock poisoned" )
109+ . extend ( [
110+ (
111+ "import_attach_to_monorepo_parent_ms" . to_string ( ) ,
112+ t_attach. elapsed ( ) . as_millis ( ) ,
113+ ) ,
114+ (
115+ "import_finalize_total_ms" . to_string ( ) ,
116+ t0. elapsed ( ) . as_millis ( ) ,
117+ ) ,
118+ ] ) ;
82119 Ok ( ( ) )
83120 }
84121
@@ -424,8 +461,18 @@ impl ImportRepo {
424461
425462 // Concurrent attaches need CAS on root mega_refs; retry when head moved.
426463 const MAX_ATTACH_ATTEMPTS : u32 = 64 ;
464+ let mut root_lock_wait_max_ms: u128 = 0 ;
465+ let mut root_lock_wait_sum_ms: u128 = 0 ;
427466
428467 for attempt in 0 ..MAX_ATTACH_ATTEMPTS {
468+ // Only the root mega_refs update needs cross-repo serialization.
469+ // Keep the lock scope as small as possible: just the root ref read + attach transaction.
470+ let t_lock = Instant :: now ( ) ;
471+ let guard = self . unpack_redlock . clone ( ) . lock ( ) . await ?;
472+ let lock_wait_ms = t_lock. elapsed ( ) . as_millis ( ) ;
473+ root_lock_wait_max_ms = root_lock_wait_max_ms. max ( lock_wait_ms) ;
474+ root_lock_wait_sum_ms += lock_wait_ms;
475+
429476 let root_ref = storage
430477 . get_main_ref ( "/" )
431478 . await ?
@@ -479,6 +526,7 @@ impl ImportRepo {
479526 }
480527 }
481528
529+ let t_attach_txn = Instant :: now ( ) ;
482530 match storage
483531 . attach_to_monorepo_parent_in_txn (
484532 & txn,
@@ -492,10 +540,38 @@ impl ImportRepo {
492540 {
493541 Ok ( ( ) ) => {
494542 txn. commit ( ) . await . map_err ( MegaError :: Db ) ?;
543+ let t_unlock = Instant :: now ( ) ;
544+ guard. unlock ( ) . await ?;
545+ self . receive_pack_extra_timings_ms
546+ . lock ( )
547+ . expect ( "receive_pack_extra_timings_ms lock poisoned" )
548+ . extend ( [
549+ (
550+ "import_attach_attempts_count" . to_string ( ) ,
551+ ( attempt + 1 ) as u128 ,
552+ ) ,
553+ (
554+ "import_root_lock_wait_sum_ms" . to_string ( ) ,
555+ root_lock_wait_sum_ms,
556+ ) ,
557+ (
558+ "import_root_lock_wait_max_ms" . to_string ( ) ,
559+ root_lock_wait_max_ms,
560+ ) ,
561+ (
562+ "import_attach_txn_ms" . to_string ( ) ,
563+ t_attach_txn. elapsed ( ) . as_millis ( ) ,
564+ ) ,
565+ (
566+ "import_root_lock_unlock_ms" . to_string ( ) ,
567+ t_unlock. elapsed ( ) . as_millis ( ) ,
568+ ) ,
569+ ] ) ;
495570 return Ok ( ( ) ) ;
496571 }
497572 Err ( MegaError :: StaleMonorepoRootRef ) if attempt + 1 < MAX_ATTACH_ATTEMPTS => {
498573 let _ = txn. rollback ( ) . await ;
574+ let _ = guard. unlock ( ) . await ;
499575 tracing:: warn!(
500576 attempt = attempt,
501577 repo_path = %self . repo. repo_path,
@@ -505,6 +581,28 @@ impl ImportRepo {
505581 }
506582 Err ( e) => {
507583 let _ = txn. rollback ( ) . await ;
584+ let _ = guard. unlock ( ) . await ;
585+ self . receive_pack_extra_timings_ms
586+ . lock ( )
587+ . expect ( "receive_pack_extra_timings_ms lock poisoned" )
588+ . extend ( [
589+ (
590+ "import_attach_attempts_count" . to_string ( ) ,
591+ ( attempt + 1 ) as u128 ,
592+ ) ,
593+ (
594+ "import_root_lock_wait_sum_ms" . to_string ( ) ,
595+ root_lock_wait_sum_ms,
596+ ) ,
597+ (
598+ "import_root_lock_wait_max_ms" . to_string ( ) ,
599+ root_lock_wait_max_ms,
600+ ) ,
601+ (
602+ "import_attach_txn_ms" . to_string ( ) ,
603+ t_attach_txn. elapsed ( ) . as_millis ( ) ,
604+ ) ,
605+ ] ) ;
508606 return Err ( e) ;
509607 }
510608 }
0 commit comments