Show More
@@ -573,10 +573,14 b' if rustmod is not None:' | |||
|
573 | 573 | testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file') |
|
574 | 574 | if not self.docket.uuid: |
|
575 | 575 | data = b'' |
|
576 | self._map = rustmod.DirstateMap.new_empty() | |
|
576 | 577 | else: |
|
577 | 578 | data = self._read_v2_data() |
|
578 | 579 | self._map = rustmod.DirstateMap.new_v2( |
|
579 | data, self.docket.data_size, self.docket.tree_metadata | |
|
580 | data, | |
|
581 | self.docket.data_size, | |
|
582 | self.docket.tree_metadata, | |
|
583 | self.docket.uuid, | |
|
580 | 584 | ) |
|
581 | 585 | parents = self.docket.parents |
|
582 | 586 | else: |
@@ -66,9 +66,16 b" pub struct DirstateMap<'on_disk> {" | |||
|
66 | 66 | pub(super) unreachable_bytes: u32, |
|
67 | 67 | |
|
68 | 68 | /// Size of the data used to first load this `DirstateMap`. Used in case |
|
69 |
/// we need to write some new metadata, but no new data on disk |
|
|
69 | /// we need to write some new metadata, but no new data on disk, | |
|
70 | /// as well as to detect writes that have happened in another process | |
|
71 | /// since first read. | |
|
70 | 72 | pub(super) old_data_size: usize, |
|
71 | 73 | |
|
74 | /// UUID used when first loading this `DirstateMap`. Used to check if | |
|
75 | /// the UUID has been changed by another process since first read. | |
|
76 | /// Can be `None` if using dirstate v1 or if it's a brand new dirstate. | |
|
77 | pub(super) old_uuid: Option<Vec<u8>>, | |
|
78 | ||
|
72 | 79 | pub(super) dirstate_version: DirstateVersion, |
|
73 | 80 | |
|
74 | 81 | /// Controlled by config option `devel.dirstate.v2.data_update_mode` |
@@ -460,6 +467,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||
|
460 | 467 | ignore_patterns_hash: [0; on_disk::IGNORE_PATTERNS_HASH_LEN], |
|
461 | 468 | unreachable_bytes: 0, |
|
462 | 469 | old_data_size: 0, |
|
470 | old_uuid: None, | |
|
463 | 471 | dirstate_version: DirstateVersion::V1, |
|
464 | 472 | write_mode: DirstateMapWriteMode::Auto, |
|
465 | 473 | } |
@@ -470,9 +478,10 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||
|
470 | 478 | on_disk: &'on_disk [u8], |
|
471 | 479 | data_size: usize, |
|
472 | 480 | metadata: &[u8], |
|
481 | uuid: Vec<u8>, | |
|
473 | 482 | ) -> Result<Self, DirstateError> { |
|
474 | 483 | if let Some(data) = on_disk.get(..data_size) { |
|
475 | Ok(on_disk::read(data, metadata)?) | |
|
484 | Ok(on_disk::read(data, metadata, uuid)?) | |
|
476 | 485 | } else { |
|
477 | 486 | Err(DirstateV2ParseError::new("not enough bytes on disk").into()) |
|
478 | 487 | } |
@@ -1843,6 +1852,7 b' mod tests {' | |||
|
1843 | 1852 | packed, |
|
1844 | 1853 | packed_len, |
|
1845 | 1854 | metadata.as_bytes(), |
|
1855 | vec![], | |
|
1846 | 1856 | )?; |
|
1847 | 1857 | |
|
1848 | 1858 | // Check that everything is accounted for |
@@ -290,6 +290,7 b' pub fn read_docket(' | |||
|
290 | 290 | pub(super) fn read<'on_disk>( |
|
291 | 291 | on_disk: &'on_disk [u8], |
|
292 | 292 | metadata: &[u8], |
|
293 | uuid: Vec<u8>, | |
|
293 | 294 | ) -> Result<DirstateMap<'on_disk>, DirstateV2ParseError> { |
|
294 | 295 | if on_disk.is_empty() { |
|
295 | 296 | let mut map = DirstateMap::empty(on_disk); |
@@ -312,6 +313,7 b" pub(super) fn read<'on_disk>(" | |||
|
312 | 313 | ignore_patterns_hash: meta.ignore_patterns_hash, |
|
313 | 314 | unreachable_bytes: meta.unreachable_bytes.get(), |
|
314 | 315 | old_data_size: on_disk.len(), |
|
316 | old_uuid: Some(uuid), | |
|
315 | 317 | dirstate_version: DirstateVersion::V2, |
|
316 | 318 | write_mode: DirstateMapWriteMode::Auto, |
|
317 | 319 | }; |
@@ -57,6 +57,7 b' impl OwningDirstateMap {' | |||
|
57 | 57 | on_disk: OnDisk, |
|
58 | 58 | data_size: usize, |
|
59 | 59 | metadata: &[u8], |
|
60 | uuid: Vec<u8>, | |
|
60 | 61 | ) -> Result<Self, DirstateError> |
|
61 | 62 | where |
|
62 | 63 | OnDisk: Deref<Target = [u8]> + Send + 'static, |
@@ -66,7 +67,7 b' impl OwningDirstateMap {' | |||
|
66 | 67 | OwningDirstateMapTryBuilder { |
|
67 | 68 | on_disk, |
|
68 | 69 | map_builder: |bytes| { |
|
69 | DirstateMap::new_v2(&bytes, data_size, metadata) | |
|
70 | DirstateMap::new_v2(&bytes, data_size, metadata, uuid) | |
|
70 | 71 | }, |
|
71 | 72 | } |
|
72 | 73 | .try_build() |
@@ -86,4 +87,12 b' impl OwningDirstateMap {' | |||
|
86 | 87 | pub fn on_disk(&self) -> &[u8] { |
|
87 | 88 | self.borrow_on_disk() |
|
88 | 89 | } |
|
90 | ||
|
91 | pub fn old_uuid(&self) -> Option<&[u8]> { | |
|
92 | self.get_map().old_uuid.as_deref() | |
|
89 | 93 | } |
|
94 | ||
|
95 | pub fn old_data_size(&self) -> usize { | |
|
96 | self.get_map().old_data_size | |
|
97 | } | |
|
98 | } |
@@ -383,6 +383,7 b' impl Repo {' | |||
|
383 | 383 | self.dirstate_parents.set(docket.parents()); |
|
384 | 384 | self.dirstate_data_file_uuid |
|
385 | 385 | .set(Some(docket.uuid.to_owned())); |
|
386 | let uuid = docket.uuid.to_owned(); | |
|
386 | 387 | let data_size = docket.data_size(); |
|
387 | 388 | |
|
388 | 389 | let context = "between reading dirstate docket and data file"; |
@@ -415,16 +416,16 b' impl Repo {' | |||
|
415 | 416 | } |
|
416 | 417 | Err(e) => return Err(e.into()), |
|
417 | 418 | }; |
|
418 | OwningDirstateMap::new_v2(contents, data_size, metadata) | |
|
419 | OwningDirstateMap::new_v2(contents, data_size, metadata, uuid) | |
|
419 | 420 | } else { |
|
420 | 421 | match self |
|
421 | 422 | .hg_vfs() |
|
422 | 423 | .mmap_open(docket.data_filename()) |
|
423 | 424 | .io_not_found_as_none() |
|
424 | 425 | { |
|
425 |
Ok(Some(data_mmap)) => |
|
|
426 |
|
|
|
427 |
|
|
|
426 | Ok(Some(data_mmap)) => OwningDirstateMap::new_v2( | |
|
427 | data_mmap, data_size, metadata, uuid, | |
|
428 | ), | |
|
428 | 429 | Ok(None) => { |
|
429 | 430 | // Race where the data file was deleted right after we |
|
430 | 431 | // read the docket, try again |
@@ -66,18 +66,28 b' py_class!(pub class DirstateMap |py| {' | |||
|
66 | 66 | on_disk: PyBytes, |
|
67 | 67 | data_size: usize, |
|
68 | 68 | tree_metadata: PyBytes, |
|
69 | uuid: PyBytes, | |
|
69 | 70 | ) -> PyResult<PyObject> { |
|
70 | 71 | let dirstate_error = |e: DirstateError| { |
|
71 | 72 | PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) |
|
72 | 73 | }; |
|
73 | 74 | let on_disk = PyBytesDeref::new(py, on_disk); |
|
75 | let uuid = uuid.data(py); | |
|
74 | 76 | let map = OwningDirstateMap::new_v2( |
|
75 | on_disk, data_size, tree_metadata.data(py), | |
|
77 | on_disk, data_size, tree_metadata.data(py), uuid.to_owned(), | |
|
76 | 78 | ).map_err(dirstate_error)?; |
|
77 | 79 | let map = Self::create_instance(py, map)?; |
|
78 | 80 | Ok(map.into_object()) |
|
79 | 81 | } |
|
80 | 82 | |
|
83 | /// Returns an empty DirstateMap. Only used for a new dirstate. | |
|
84 | @staticmethod | |
|
85 | def new_empty() -> PyResult<PyObject> { | |
|
86 | let map = OwningDirstateMap::new_empty(vec![]); | |
|
87 | let map = Self::create_instance(py, map)?; | |
|
88 | Ok(map.into_object()) | |
|
89 | } | |
|
90 | ||
|
81 | 91 | def clear(&self) -> PyResult<PyObject> { |
|
82 | 92 | self.inner(py).borrow_mut().clear(); |
|
83 | 93 | Ok(py.None()) |
General Comments 0
You need to be logged in to leave comments.
Login now