Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-core/src/repo.rs @ 49200:10b9f11daf15
branching: merge stable into default
This also added the small fix need in Rust tests for the new
`DirstateMap::pack_v2` API change in stable.
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Mon, 25 Apr 2022 11:09:33 +0200 |
parents | 3f5e207f78be 802e2c25dab8 |
children | a932cad26d37 |
line wrap: on
line diff
--- a/rust/hg-core/src/repo.rs Tue Apr 19 12:17:23 2022 -0700 +++ b/rust/hg-core/src/repo.rs Mon Apr 25 11:09:33 2022 +0200 @@ -423,22 +423,25 @@ // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if // it’s unset let parents = self.dirstate_parents()?; - let packed_dirstate = if self.has_dirstate_v2() { + let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() { let uuid = self.dirstate_data_file_uuid.get_or_init(self)?; let mut uuid = uuid.as_ref(); let can_append = uuid.is_some(); - let (data, tree_metadata, append) = map.pack_v2(can_append)?; + let (data, tree_metadata, append, old_data_size) = + map.pack_v2(can_append)?; if !append { uuid = None } - let uuid = if let Some(uuid) = uuid { - std::str::from_utf8(uuid) + let (uuid, old_uuid) = if let Some(uuid) = uuid { + let as_str = std::str::from_utf8(uuid) .map_err(|_| { HgError::corrupted("non-UTF-8 dirstate data file ID") })? - .to_owned() + .to_owned(); + let old_uuid_to_remove = Some(as_str.to_owned()); + (as_str, old_uuid_to_remove) } else { - DirstateDocket::new_uid() + (DirstateDocket::new_uid(), None) }; let data_filename = format!("dirstate.{}", uuid); let data_filename = self.hg_vfs().join(data_filename); @@ -453,13 +456,23 @@ // returns `ErrorKind::AlreadyExists`? Collision chance of two // random IDs is one in 2**32 let mut file = options.open(&data_filename)?; - file.write_all(&data)?; - file.flush()?; - // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ - file.seek(SeekFrom::Current(0)) + if data.is_empty() { + // If we're not appending anything, the data size is the + // same as in the previous docket. It is *not* the file + // length, since it could have garbage at the end. + // We don't have to worry about it when we do have data + // to append since we rewrite the root node in this case. + Ok(old_data_size as u64) + } else { + file.write_all(&data)?; + file.flush()?; + // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ + file.seek(SeekFrom::Current(0)) + } })() .when_writing_file(&data_filename)?; - DirstateDocket::serialize( + + let packed_dirstate = DirstateDocket::serialize( parents, tree_metadata, data_size, @@ -467,11 +480,20 @@ ) .map_err(|_: std::num::TryFromIntError| { HgError::corrupted("overflow in dirstate docket serialization") - })? + })?; + + (packed_dirstate, old_uuid) } else { - map.pack_v1(parents)? + (map.pack_v1(parents)?, None) }; - self.hg_vfs().atomic_write("dirstate", &packed_dirstate)?; + + let vfs = self.hg_vfs(); + vfs.atomic_write("dirstate", &packed_dirstate)?; + if let Some(uuid) = old_uuid_to_remove { + // Remove the old data file after the new docket pointing to the + // new data file was written. + vfs.remove_file(format!("dirstate.{}", uuid))?; + } Ok(()) } }