annotate rust/hg-core/src/dirstate_tree/owning.rs @ 49703:dbe09fb038fc stable

rhg: remember the inode of .hg/dirstate This allows us to detect changes of `.hg/dirstate`, which is either the full dirstate (in dirstate-v1) or the docket file (v2) without relying on data inside the file. It only works on UNIX systems. This fixes a race condition for dirstate-v1 (as demonstrated by the test changes) and adds a confortable layer of sanity for dirstate-v2.
author Rapha?l Gom?s <rgomes@octobus.net>
date Wed, 01 Mar 2023 16:48:09 +0100
parents 6cce0afc1454
children a6b8b1ab9116
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
1 use crate::{DirstateError, DirstateParents};
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
2
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
3 use super::dirstate_map::DirstateMap;
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
4 use std::ops::Deref;
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
5
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
6 use ouroboros::self_referencing;
48824
cfd270d83169 rust: explain why the current `OwningDirstateMap` is unsound
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48595
diff changeset
7
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 /// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
9 /// borrows.
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
10 #[self_referencing]
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
11 pub struct OwningDirstateMap {
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
12 on_disk: Box<dyn Deref<Target = [u8]> + Send>,
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
13 #[borrows(on_disk)]
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
14 #[covariant]
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
15 map: DirstateMap<'this>,
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16 }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18 impl OwningDirstateMap {
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
19 pub fn new_empty<OnDisk>(on_disk: OnDisk) -> Self
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
20 where
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
21 OnDisk: Deref<Target = [u8]> + Send + 'static,
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
22 {
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
23 let on_disk = Box::new(on_disk);
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
24
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
25 OwningDirstateMapBuilder {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
26 on_disk,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
27 map_builder: |bytes| DirstateMap::empty(&bytes),
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
28 }
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
29 .build()
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
30 }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
31
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
32 pub fn new_v1<OnDisk>(
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
33 on_disk: OnDisk,
49703
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
34 identity: Option<u64>,
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
35 ) -> Result<(Self, DirstateParents), DirstateError>
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
36 where
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
37 OnDisk: Deref<Target = [u8]> + Send + 'static,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
38 {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
39 let on_disk = Box::new(on_disk);
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
40 let mut parents = DirstateParents::NULL;
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
41
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
42 Ok((
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
43 OwningDirstateMapTryBuilder {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
44 on_disk,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
45 map_builder: |bytes| {
49703
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
46 DirstateMap::new_v1(&bytes, identity).map(|(dmap, p)| {
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
47 parents = p.unwrap_or(DirstateParents::NULL);
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
48 dmap
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
49 })
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
50 },
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
51 }
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
52 .try_build()?,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
53 parents,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
54 ))
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
55 }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
56
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
57 pub fn new_v2<OnDisk>(
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
58 on_disk: OnDisk,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
59 data_size: usize,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
60 metadata: &[u8],
49701
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
61 uuid: Vec<u8>,
49703
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
62 identity: Option<u64>,
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
63 ) -> Result<Self, DirstateError>
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
64 where
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
65 OnDisk: Deref<Target = [u8]> + Send + 'static,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
66 {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
67 let on_disk = Box::new(on_disk);
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
68
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
69 OwningDirstateMapTryBuilder {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
70 on_disk,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
71 map_builder: |bytes| {
49703
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
72 DirstateMap::new_v2(
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
73 &bytes, data_size, metadata, uuid, identity,
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
74 )
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
75 },
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
76 }
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
77 .try_build()
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
78 }
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
79
48825
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
80 pub fn with_dmap_mut<R>(
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
81 &mut self,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
82 f: impl FnOnce(&mut DirstateMap) -> R,
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
83 ) -> R {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
84 self.with_map_mut(f)
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
85 }
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
86
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
87 pub fn get_map(&self) -> &DirstateMap {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
88 self.borrow_map()
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
89 }
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
90
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
91 pub fn on_disk(&self) -> &[u8] {
dd6b67d5c256 rust: fix unsound `OwningDirstateMap`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48824
diff changeset
92 self.borrow_on_disk()
47982
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
93 }
49701
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
94
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
95 pub fn old_uuid(&self) -> Option<&[u8]> {
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
96 self.get_map().old_uuid.as_deref()
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
97 }
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
98
49703
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
99 pub fn old_identity(&self) -> Option<u64> {
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
100 self.get_map().identity
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
101 }
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49701
diff changeset
102
49701
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
103 pub fn old_data_size(&self) -> usize {
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
104 self.get_map().old_data_size
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48825
diff changeset
105 }
47137
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106 }