@@ -459,14 +459,29 @@ impl ImportRepo {
459459 let mono_api_service: MonoApiService = self . into ( ) ;
460460 let storage = self . storage . mono_storage ( ) ;
461461
462+ // Import tip commit + message do not depend on monorepo root; load once so retries
463+ // under the root lock do not repeat git_db reads.
464+ let latest_commit: Commit = Commit :: from_git_model (
465+ self . storage
466+ . git_db_storage ( )
467+ . get_commit_by_hash ( self . repo . repo_id , & commit_id)
468+ . await ?
469+ . ok_or_else ( || MegaError :: Other ( format ! ( "commit {commit_id} not found" ) ) ) ?,
470+ ) ;
471+ let commit_msg = latest_commit. format_message ( ) ;
472+
462473 // Concurrent attaches need CAS on root mega_refs; retry when head moved.
474+ // Redis lock reduces retry storms; DB still enforces correctness via StaleMonorepoRootRef.
475+ //
476+ // `search_and_create_tree` walks the live root tree via the API (`get_root_tree`); it must
477+ // run against the same root snapshot as `get_main_ref` for this attempt, so it stays
478+ // inside the locked section. Further reduction would require threading an explicit root
479+ // tree/commit into `tree_ops` so tree building can run without holding the global lock.
463480 const MAX_ATTACH_ATTEMPTS : u32 = 64 ;
464481 let mut root_lock_wait_max_ms: u128 = 0 ;
465482 let mut root_lock_wait_sum_ms: u128 = 0 ;
466483
467484 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.
470485 let t_lock = Instant :: now ( ) ;
471486 let guard = self . unpack_redlock . clone ( ) . lock ( ) . await ?;
472487 let lock_wait_ms = t_lock. elapsed ( ) . as_millis ( ) ;
@@ -483,15 +498,6 @@ impl ImportRepo {
483498
484499 let save_trees = tree_ops:: search_and_create_tree ( & mono_api_service, & path) . await ?;
485500
486- let latest_commit: Commit = Commit :: from_git_model (
487- self . storage
488- . git_db_storage ( )
489- . get_commit_by_hash ( self . repo . repo_id , & commit_id)
490- . await ?
491- . ok_or_else ( || MegaError :: Other ( format ! ( "commit {} not found" , commit_id) ) ) ?,
492- ) ;
493-
494- let commit_msg = latest_commit. format_message ( ) ;
495501 let new_commit = Commit :: from_tree_id (
496502 save_trees
497503 . back ( )
0 commit comments