Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-core/src/repo.rs @ 50389:bf16ef96defe stable
rust-dirstate: fall back to v1 if reading v2 failed
This will help us not fail when a v1 dirstate is present on disk while a v2
was expected (which could happen with a racy/interrupted upgrade).
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Mon, 05 Jun 2023 16:43:27 +0200 |
parents | 1e2c6cda2309 |
children | 1928b770e3e7 |
line wrap: on
line diff
--- a/rust/hg-core/src/repo.rs Mon Jun 05 17:29:52 2023 +0200 +++ b/rust/hg-core/src/repo.rs Mon Jun 05 16:43:27 2023 +0200 @@ -238,9 +238,10 @@ /// a dirstate-v2 file will indeed be found, but in rare cases (like the /// upgrade mechanism being cut short), the on-disk version will be a /// v1 file. - /// Semantically, having a requirement only means that a client should be - /// able to understand the repo *if* it uses the requirement, but not that - /// the requirement is actually used. + /// Semantically, having a requirement only means that a client cannot + /// properly understand or properly update the repo if it lacks the support + /// for the required feature, but not that that feature is actually used + /// in all occasions. pub fn use_dirstate_v2(&self) -> bool { self.requirements .contains(requirements::DIRSTATE_V2_REQUIREMENT) @@ -287,9 +288,20 @@ let parents = if dirstate.is_empty() { DirstateParents::NULL } else if self.use_dirstate_v2() { - let docket = - crate::dirstate_tree::on_disk::read_docket(&dirstate)?; - docket.parents() + let docket_res = + crate::dirstate_tree::on_disk::read_docket(&dirstate); + match docket_res { + Ok(docket) => docket.parents(), + Err(_) => { + log::info!( + "Parsing dirstate docket failed, \ + falling back to dirstate-v1" + ); + *crate::dirstate::parsers::parse_dirstate_parents( + &dirstate, + )? + } + } } else { *crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? }; @@ -317,10 +329,30 @@ self.dirstate_parents.set(DirstateParents::NULL); Ok((identity, None, 0)) } else { - let docket = - crate::dirstate_tree::on_disk::read_docket(&dirstate)?; - self.dirstate_parents.set(docket.parents()); - Ok((identity, Some(docket.uuid.to_owned()), docket.data_size())) + let docket_res = + crate::dirstate_tree::on_disk::read_docket(&dirstate); + match docket_res { + Ok(docket) => { + self.dirstate_parents.set(docket.parents()); + Ok(( + identity, + Some(docket.uuid.to_owned()), + docket.data_size(), + )) + } + Err(_) => { + log::info!( + "Parsing dirstate docket failed, \ + falling back to dirstate-v1" + ); + let parents = + *crate::dirstate::parsers::parse_dirstate_parents( + &dirstate, + )?; + self.dirstate_parents.set(parents); + Ok((identity, None, 0)) + } + } } } @@ -352,7 +384,13 @@ ); continue; } - _ => return Err(e), + _ => { + log::info!( + "Reading dirstate v2 failed, \ + falling back to v1" + ); + return self.new_dirstate_map_v1(); + } }, } } @@ -363,23 +401,22 @@ ); Err(DirstateError::Common(error)) } else { - debug_wait_for_file_or_print( - self.config(), - "dirstate.pre-read-file", - ); - let identity = self.dirstate_identity()?; - let dirstate_file_contents = self.dirstate_file_contents()?; - if dirstate_file_contents.is_empty() { - self.dirstate_parents.set(DirstateParents::NULL); - Ok(OwningDirstateMap::new_empty(Vec::new())) - } else { - let (map, parents) = OwningDirstateMap::new_v1( - dirstate_file_contents, - identity, - )?; - self.dirstate_parents.set(parents); - Ok(map) - } + self.new_dirstate_map_v1() + } + } + + fn new_dirstate_map_v1(&self) -> Result<OwningDirstateMap, DirstateError> { + debug_wait_for_file_or_print(self.config(), "dirstate.pre-read-file"); + let identity = self.dirstate_identity()?; + let dirstate_file_contents = self.dirstate_file_contents()?; + if dirstate_file_contents.is_empty() { + self.dirstate_parents.set(DirstateParents::NULL); + Ok(OwningDirstateMap::new_empty(Vec::new())) + } else { + let (map, parents) = + OwningDirstateMap::new_v1(dirstate_file_contents, identity)?; + self.dirstate_parents.set(parents); + Ok(map) } }