Mercurial > hg
changeset 50243:6cce0afc1454 stable
rust-dirstate: remember the data file uuid dirstate was loaded with
This will be used in the next patch to fix a race condition.
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Mon, 12 Dec 2022 17:08:12 +0100 |
parents | 379a78001d8e |
children | 07d030b38097 |
files | mercurial/dirstatemap.py rust/hg-core/src/dirstate_tree/dirstate_map.rs rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-core/src/dirstate_tree/owning.rs rust/hg-core/src/repo.rs rust/hg-cpython/src/dirstate/dirstate_map.rs |
diffstat | 6 files changed, 47 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/dirstatemap.py Wed Mar 01 02:38:20 2023 +0100 +++ b/mercurial/dirstatemap.py Mon Dec 12 17:08:12 2022 +0100 @@ -573,11 +573,15 @@ testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file') if not self.docket.uuid: data = b'' + self._map = rustmod.DirstateMap.new_empty() else: data = self._read_v2_data() - self._map = rustmod.DirstateMap.new_v2( - data, self.docket.data_size, self.docket.tree_metadata - ) + self._map = rustmod.DirstateMap.new_v2( + data, + self.docket.data_size, + self.docket.tree_metadata, + self.docket.uuid, + ) parents = self.docket.parents else: self._set_identity()
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Wed Mar 01 02:38:20 2023 +0100 +++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Mon Dec 12 17:08:12 2022 +0100 @@ -66,9 +66,16 @@ pub(super) unreachable_bytes: u32, /// Size of the data used to first load this `DirstateMap`. Used in case - /// we need to write some new metadata, but no new data on disk. + /// we need to write some new metadata, but no new data on disk, + /// as well as to detect writes that have happened in another process + /// since first read. pub(super) old_data_size: usize, + /// UUID used when first loading this `DirstateMap`. Used to check if + /// the UUID has been changed by another process since first read. + /// Can be `None` if using dirstate v1 or if it's a brand new dirstate. + pub(super) old_uuid: Option<Vec<u8>>, + pub(super) dirstate_version: DirstateVersion, /// Controlled by config option `devel.dirstate.v2.data_update_mode` @@ -460,6 +467,7 @@ ignore_patterns_hash: [0; on_disk::IGNORE_PATTERNS_HASH_LEN], unreachable_bytes: 0, old_data_size: 0, + old_uuid: None, dirstate_version: DirstateVersion::V1, write_mode: DirstateMapWriteMode::Auto, } @@ -470,9 +478,10 @@ on_disk: &'on_disk [u8], data_size: usize, metadata: &[u8], + uuid: Vec<u8>, ) -> Result<Self, DirstateError> { if let Some(data) = on_disk.get(..data_size) { - Ok(on_disk::read(data, metadata)?) + Ok(on_disk::read(data, metadata, uuid)?) } else { Err(DirstateV2ParseError::new("not enough bytes on disk").into()) } @@ -1843,6 +1852,7 @@ packed, packed_len, metadata.as_bytes(), + vec![], )?; // Check that everything is accounted for
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs Wed Mar 01 02:38:20 2023 +0100 +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs Mon Dec 12 17:08:12 2022 +0100 @@ -290,6 +290,7 @@ pub(super) fn read<'on_disk>( on_disk: &'on_disk [u8], metadata: &[u8], + uuid: Vec<u8>, ) -> Result<DirstateMap<'on_disk>, DirstateV2ParseError> { if on_disk.is_empty() { let mut map = DirstateMap::empty(on_disk); @@ -312,6 +313,7 @@ ignore_patterns_hash: meta.ignore_patterns_hash, unreachable_bytes: meta.unreachable_bytes.get(), old_data_size: on_disk.len(), + old_uuid: Some(uuid), dirstate_version: DirstateVersion::V2, write_mode: DirstateMapWriteMode::Auto, };
--- a/rust/hg-core/src/dirstate_tree/owning.rs Wed Mar 01 02:38:20 2023 +0100 +++ b/rust/hg-core/src/dirstate_tree/owning.rs Mon Dec 12 17:08:12 2022 +0100 @@ -57,6 +57,7 @@ on_disk: OnDisk, data_size: usize, metadata: &[u8], + uuid: Vec<u8>, ) -> Result<Self, DirstateError> where OnDisk: Deref<Target = [u8]> + Send + 'static, @@ -66,7 +67,7 @@ OwningDirstateMapTryBuilder { on_disk, map_builder: |bytes| { - DirstateMap::new_v2(&bytes, data_size, metadata) + DirstateMap::new_v2(&bytes, data_size, metadata, uuid) }, } .try_build() @@ -86,4 +87,12 @@ pub fn on_disk(&self) -> &[u8] { self.borrow_on_disk() } + + pub fn old_uuid(&self) -> Option<&[u8]> { + self.get_map().old_uuid.as_deref() + } + + pub fn old_data_size(&self) -> usize { + self.get_map().old_data_size + } }
--- a/rust/hg-core/src/repo.rs Wed Mar 01 02:38:20 2023 +0100 +++ b/rust/hg-core/src/repo.rs Mon Dec 12 17:08:12 2022 +0100 @@ -383,6 +383,7 @@ self.dirstate_parents.set(docket.parents()); self.dirstate_data_file_uuid .set(Some(docket.uuid.to_owned())); + let uuid = docket.uuid.to_owned(); let data_size = docket.data_size(); let context = "between reading dirstate docket and data file"; @@ -415,16 +416,16 @@ } Err(e) => return Err(e.into()), }; - OwningDirstateMap::new_v2(contents, data_size, metadata) + OwningDirstateMap::new_v2(contents, data_size, metadata, uuid) } else { match self .hg_vfs() .mmap_open(docket.data_filename()) .io_not_found_as_none() { - Ok(Some(data_mmap)) => { - OwningDirstateMap::new_v2(data_mmap, data_size, metadata) - } + Ok(Some(data_mmap)) => OwningDirstateMap::new_v2( + data_mmap, data_size, metadata, uuid, + ), Ok(None) => { // Race where the data file was deleted right after we // read the docket, try again
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Wed Mar 01 02:38:20 2023 +0100 +++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Mon Dec 12 17:08:12 2022 +0100 @@ -66,18 +66,28 @@ on_disk: PyBytes, data_size: usize, tree_metadata: PyBytes, + uuid: PyBytes, ) -> PyResult<PyObject> { let dirstate_error = |e: DirstateError| { PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) }; let on_disk = PyBytesDeref::new(py, on_disk); + let uuid = uuid.data(py); let map = OwningDirstateMap::new_v2( - on_disk, data_size, tree_metadata.data(py), + on_disk, data_size, tree_metadata.data(py), uuid.to_owned(), ).map_err(dirstate_error)?; let map = Self::create_instance(py, map)?; Ok(map.into_object()) } + /// Returns an empty DirstateMap. Only used for a new dirstate. + @staticmethod + def new_empty() -> PyResult<PyObject> { + let map = OwningDirstateMap::new_empty(vec![]); + let map = Self::create_instance(py, map)?; + Ok(map.into_object()) + } + def clear(&self) -> PyResult<PyObject> { self.inner(py).borrow_mut().clear(); Ok(py.None())