diff options
Diffstat (limited to 'vendor/gix/src/remote/connection/fetch/receive_pack.rs')
-rw-r--r-- | vendor/gix/src/remote/connection/fetch/receive_pack.rs | 129 |
1 files changed, 74 insertions, 55 deletions
diff --git a/vendor/gix/src/remote/connection/fetch/receive_pack.rs b/vendor/gix/src/remote/connection/fetch/receive_pack.rs index 7837a9d3a..18e5ac159 100644 --- a/vendor/gix/src/remote/connection/fetch/receive_pack.rs +++ b/vendor/gix/src/remote/connection/fetch/receive_pack.rs @@ -19,17 +19,18 @@ use crate::{ connection::fetch::config, fetch, fetch::{ - negotiate, negotiate::Algorithm, refs, Error, Outcome, Prepare, ProgressId, RefLogMessage, Shallow, Status, + negotiate, negotiate::Algorithm, outcome, refs, Error, Outcome, Prepare, ProgressId, RefLogMessage, + Shallow, Status, }, }, - Progress, Repository, + Repository, }; impl<'remote, 'repo, T> Prepare<'remote, 'repo, T> where T: Transport, { - /// Receive the pack and perform the operation as configured by git via `gix-config` or overridden by various builder methods. + /// Receive the pack and perform the operation as configured by git via `git-config` or overridden by various builder methods. /// Return `Ok(None)` if there was nothing to do because all remote refs are at the same state as they are locally, or `Ok(Some(outcome))` /// to inform about all the changes that were made. /// @@ -72,18 +73,28 @@ where /// - `gitoxide.userAgent` is read to obtain the application user agent for git servers and for HTTP servers as well. /// #[gix_protocol::maybe_async::maybe_async] - pub async fn receive<P>(mut self, mut progress: P, should_interrupt: &AtomicBool) -> Result<Outcome, Error> + pub async fn receive<P>(self, mut progress: P, should_interrupt: &AtomicBool) -> Result<Outcome, Error> where - P: Progress, + P: gix_features::progress::NestedProgress, P::SubProgress: 'static, { + self.receive_inner(&mut progress, should_interrupt).await + } + + #[gix_protocol::maybe_async::maybe_async] + #[allow(clippy::drop_non_drop)] + pub(crate) async fn receive_inner( + mut self, + progress: &mut dyn crate::DynNestedProgress, + should_interrupt: &AtomicBool, + ) -> Result<Outcome, Error> { + let _span = gix_trace::coarse!("fetch::Prepare::receive()"); let mut con = self.con.take().expect("receive() can only be called once"); let handshake = &self.ref_map.handshake; let protocol_version = handshake.server_protocol_version; let fetch = gix_protocol::Command::Fetch; - let progress = &mut progress; let repo = con.remote.repo; let fetch_features = { let mut f = fetch.default_features(protocol_version, &handshake.capabilities); @@ -114,6 +125,7 @@ where }); } + let negotiate_span = gix_trace::detail!("negotiate"); let mut negotiator = repo .config .resolved @@ -131,20 +143,20 @@ where r.objects.unset_object_cache(); r }; - let mut graph = graph_repo.commit_graph(); + let mut graph = graph_repo.revision_graph(); let action = negotiate::mark_complete_and_common_ref( &graph_repo, negotiator.deref_mut(), &mut graph, &self.ref_map, &self.shallow, + negotiate::make_refmapping_ignore_predicate(con.remote.fetch_tags, &self.ref_map), )?; let mut previous_response = None::<gix_protocol::fetch::Response>; - let mut round = 1; - let mut write_pack_bundle = match &action { + let (mut write_pack_bundle, negotiate) = match &action { negotiate::Action::NoChange | negotiate::Action::SkipToRefUpdate => { gix_protocol::indicate_end_of_interaction(&mut con.transport).await.ok(); - None + (None, None) } negotiate::Action::MustNegotiate { remote_ref_target_known, @@ -155,17 +167,19 @@ where &self.ref_map, remote_ref_target_known, &self.shallow, - con.remote.fetch_tags, + negotiate::make_refmapping_ignore_predicate(con.remote.fetch_tags, &self.ref_map), ); + let mut rounds = Vec::new(); let is_stateless = arguments.is_stateless(!con.transport.connection_persists_across_multiple_requests()); let mut haves_to_send = gix_negotiate::window_size(is_stateless, None); let mut seen_ack = false; let mut in_vain = 0; let mut common = is_stateless.then(Vec::new); - let reader = 'negotiation: loop { + let mut reader = 'negotiation: loop { + let _round = gix_trace::detail!("negotiate round", round = rounds.len() + 1); progress.step(); - progress.set_name(format!("negotiate (round {round})")); + progress.set_name(format!("negotiate (round {})", rounds.len() + 1)); let is_done = match negotiate::one_round( negotiator.deref_mut(), @@ -181,8 +195,14 @@ where } seen_ack |= ack_seen; in_vain += haves_sent; + rounds.push(outcome::negotiate::Round { + haves_sent, + in_vain, + haves_to_send, + previous_response_had_at_least_one_in_common: ack_seen, + }); let is_done = haves_sent != haves_to_send || (seen_ack && in_vain >= 256); - haves_to_send = gix_negotiate::window_size(is_stateless, haves_to_send); + haves_to_send = gix_negotiate::window_size(is_stateless, Some(haves_to_send)); is_done } Err(err) => { @@ -200,17 +220,17 @@ where previous_response = Some(response); if has_pack { progress.step(); - progress.set_name("receiving pack"); + progress.set_name("receiving pack".into()); if !sideband_all { setup_remote_progress(progress, &mut reader, should_interrupt); } break 'negotiation reader; - } else { - round += 1; } }; - drop(graph); + let graph = graph.detach(); drop(graph_repo); + drop(negotiate_span); + let previous_response = previous_response.expect("knowledge of a pack means a response was received"); if !previous_response.shallow_updates().is_empty() && shallow_lock.is_none() { let reject_shallow_remote = repo @@ -234,28 +254,34 @@ where }; let write_pack_bundle = if matches!(self.dry_run, fetch::DryRun::No) { - Some(gix_pack::Bundle::write_to_directory( - #[cfg(feature = "async-network-client")] - { - gix_protocol::futures_lite::io::BlockOn::new(reader) - }, - #[cfg(not(feature = "async-network-client"))] - { - reader - }, - Some(repo.objects.store_ref().path().join("pack")), + #[cfg(not(feature = "async-network-client"))] + let mut rd = reader; + #[cfg(feature = "async-network-client")] + let mut rd = gix_protocol::futures_lite::io::BlockOn::new(reader); + let res = gix_pack::Bundle::write_to_directory( + &mut rd, + Some(&repo.objects.store_ref().path().join("pack")), progress, should_interrupt, Some(Box::new({ let repo = repo.clone(); - move |oid, buf| repo.objects.find(oid, buf).ok() + move |oid, buf| repo.objects.find(&oid, buf).ok() })), options, - )?) + )?; + #[cfg(feature = "async-network-client")] + { + reader = rd.into_inner(); + } + #[cfg(not(feature = "async-network-client"))] + { + reader = rd; + } + Some(res) } else { - drop(reader); None }; + drop(reader); if matches!(protocol_version, gix_protocol::transport::Protocol::V2) { gix_protocol::indicate_end_of_interaction(&mut con.transport).await.ok(); @@ -266,7 +292,7 @@ where crate::shallow::write(shallow_lock, shallow_commits, previous_response.shallow_updates())?; } } - write_pack_bundle + (write_pack_bundle, Some(outcome::Negotiate { graph, rounds })) } }; @@ -293,21 +319,17 @@ where let out = Outcome { ref_map: std::mem::take(&mut self.ref_map), - status: if matches!(self.dry_run, fetch::DryRun::Yes) { - assert!(write_pack_bundle.is_none(), "in dry run we never read a bundle"); - Status::DryRun { + status: match write_pack_bundle { + Some(write_pack_bundle) => Status::Change { + write_pack_bundle, update_refs, - negotiation_rounds: round, - } - } else { - match write_pack_bundle { - Some(write_pack_bundle) => Status::Change { - write_pack_bundle, - update_refs, - negotiation_rounds: round, - }, - None => Status::NoPackReceived { update_refs }, - } + negotiate: negotiate.expect("if we have a pack, we always negotiated it"), + }, + None => Status::NoPackReceived { + dry_run: matches!(self.dry_run, fetch::DryRun::Yes), + negotiate, + update_refs, + }, }, }; Ok(out) @@ -348,14 +370,14 @@ fn add_shallow_args( args.deepen_relative(); } Shallow::Since { cutoff } => { - args.deepen_since(cutoff.seconds_since_unix_epoch as usize); + args.deepen_since(cutoff.seconds); } Shallow::Exclude { remote_refs, since_cutoff, } => { if let Some(cutoff) = since_cutoff { - args.deepen_since(cutoff.seconds_since_unix_epoch as usize); + args.deepen_since(cutoff.seconds); } for ref_ in remote_refs { args.deepen_not(ref_.as_ref().as_bstr()); @@ -365,17 +387,14 @@ fn add_shallow_args( Ok((shallow_commits, shallow_lock)) } -fn setup_remote_progress<P>( - progress: &mut P, +fn setup_remote_progress( + progress: &mut dyn crate::DynNestedProgress, reader: &mut Box<dyn gix_protocol::transport::client::ExtendedBufRead + Unpin + '_>, should_interrupt: &AtomicBool, -) where - P: Progress, - P::SubProgress: 'static, -{ +) { use gix_protocol::transport::client::ExtendedBufRead; reader.set_progress_handler(Some(Box::new({ - let mut remote_progress = progress.add_child_with_id("remote", ProgressId::RemoteProgress.into()); + let mut remote_progress = progress.add_child_with_id("remote".to_string(), ProgressId::RemoteProgress.into()); // SAFETY: Ugh, so, with current Rust I can't declare lifetimes in the involved traits the way they need to // be and I also can't use scoped threads to pump from local scopes to an Arc version that could be // used here due to the this being called from sync AND async code (and the async version doesn't work |