author | Raphaël Gomès <rgomes@octobus.net> |
Mon, 12 Jun 2023 10:50:00 +0200 | |
branch | stable |
changeset 50395 | e7a3611181aa |
parent 49751 | 048f829a445a |
child 51118 | 532e74ad3ff6 |
permissions | -rw-r--r-- |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
1 |
use crate::errors::{HgError, HgResultExt}; |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
2 |
use bytes_cast::{unaligned, BytesCast}; |
47983
e834b79def74
rust: Switch to the memmap2-rs crate
Simon Sapin <simon.sapin@octobus.net>
parents:
46669
diff
changeset
|
3 |
use memmap2::Mmap; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
4 |
use std::path::{Path, PathBuf}; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
5 |
|
49141
704e993e8ee9
rust-nodemap-docket: make unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents:
49140
diff
changeset
|
6 |
use crate::vfs::Vfs; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
7 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
8 |
const ONDISK_VERSION: u8 = 1; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
9 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
10 |
pub(super) struct NodeMapDocket { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
11 |
pub data_length: usize, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
12 |
// TODO: keep here more of the data from `parse()` when we need it |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
13 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
14 |
|
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
15 |
#[derive(BytesCast)] |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
16 |
#[repr(C)] |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
17 |
struct DocketHeader { |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
18 |
uid_size: u8, |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
19 |
_tip_rev: unaligned::U64Be, |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
20 |
data_length: unaligned::U64Be, |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
21 |
_data_unused: unaligned::U64Be, |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
22 |
tip_node_size: unaligned::U64Be, |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
23 |
} |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
24 |
|
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
25 |
impl NodeMapDocket { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
26 |
/// Return `Ok(None)` when the caller should proceed without a persistent |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
27 |
/// nodemap: |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
28 |
/// |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
29 |
/// * This revlog does not have a `.n` docket file (it is not generated for |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
30 |
/// small revlogs), or |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
31 |
/// * The docket has an unsupported version number (repositories created by |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
32 |
/// later hg, maybe that should be a requirement instead?), or |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
33 |
/// * The docket file points to a missing (likely deleted) data file (this |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
34 |
/// can happen in a rare race condition). |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
35 |
pub fn read_from_file( |
49141
704e993e8ee9
rust-nodemap-docket: make unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents:
49140
diff
changeset
|
36 |
store_vfs: &Vfs, |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
37 |
index_path: &Path, |
47991
001d747c2baf
rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents:
47983
diff
changeset
|
38 |
) -> Result<Option<(Self, Mmap)>, HgError> { |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
39 |
let docket_path = index_path.with_extension("n"); |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
40 |
let docket_bytes = if let Some(bytes) = |
49141
704e993e8ee9
rust-nodemap-docket: make unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents:
49140
diff
changeset
|
41 |
store_vfs.read(&docket_path).io_not_found_as_none()? |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
42 |
{ |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
43 |
bytes |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
44 |
} else { |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
45 |
return Ok(None); |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
46 |
}; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
47 |
|
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
48 |
let input = if let Some((&ONDISK_VERSION, rest)) = |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
49 |
docket_bytes.split_first() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
50 |
{ |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
51 |
rest |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
52 |
} else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
53 |
return Ok(None); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
54 |
}; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
55 |
|
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
56 |
/// Treat any error as a parse error |
47991
001d747c2baf
rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents:
47983
diff
changeset
|
57 |
fn parse<T, E>(result: Result<T, E>) -> Result<T, HgError> { |
001d747c2baf
rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents:
47983
diff
changeset
|
58 |
result |
001d747c2baf
rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents:
47983
diff
changeset
|
59 |
.map_err(|_| HgError::corrupted("nodemap docket parse error")) |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
60 |
} |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
61 |
|
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
62 |
let (header, rest) = parse(DocketHeader::from_bytes(input))?; |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
63 |
let uid_size = header.uid_size as usize; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
64 |
// TODO: do we care about overflow for 4 GB+ nodemap files on 32-bit |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
65 |
// systems? |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
66 |
let tip_node_size = header.tip_node_size.get() as usize; |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
67 |
let data_length = header.data_length.get() as usize; |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
68 |
let (uid, rest) = parse(u8::slice_from_bytes(rest, uid_size))?; |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
69 |
let (_tip_node, _rest) = |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
70 |
parse(u8::slice_from_bytes(rest, tip_node_size))?; |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
71 |
let uid = parse(std::str::from_utf8(uid))?; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
72 |
let docket = NodeMapDocket { data_length }; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
73 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
74 |
let data_path = rawdata_path(&docket_path, uid); |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
75 |
// TODO: use `vfs.read()` here when the `persistent-nodemap.mmap` |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
76 |
// config is false? |
49141
704e993e8ee9
rust-nodemap-docket: make unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents:
49140
diff
changeset
|
77 |
if let Some(mmap) = |
704e993e8ee9
rust-nodemap-docket: make unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents:
49140
diff
changeset
|
78 |
store_vfs.mmap_open(&data_path).io_not_found_as_none()? |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
79 |
{ |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
80 |
if mmap.len() >= data_length { |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
81 |
Ok(Some((docket, mmap))) |
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
82 |
} else { |
47991
001d747c2baf
rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents:
47983
diff
changeset
|
83 |
Err(HgError::corrupted("persistent nodemap too short")) |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
84 |
} |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
85 |
} else { |
46669
842f2372ced6
rhg: Don’t attempt to read persistent nodemap without .hg/requires opt-in
Simon Sapin <simon.sapin@octobus.net>
parents:
46511
diff
changeset
|
86 |
// Even if .hg/requires opted in, some revlogs are deemed small |
842f2372ced6
rhg: Don’t attempt to read persistent nodemap without .hg/requires opt-in
Simon Sapin <simon.sapin@octobus.net>
parents:
46511
diff
changeset
|
87 |
// enough to not need a persistent nodemap. |
46511
43d63979a75e
rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents:
46462
diff
changeset
|
88 |
Ok(None) |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
89 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
90 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
91 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
92 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
93 |
fn rawdata_path(docket_path: &Path, uid: &str) -> PathBuf { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
94 |
let docket_name = docket_path |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
95 |
.file_name() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
96 |
.expect("expected a base name") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
97 |
.to_str() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
98 |
.expect("expected an ASCII file name in the store"); |
49751
048f829a445a
hg-core: remove unneeded util now that we support Rust 1.42+
Raphaël Gomès <rgomes@octobus.net>
parents:
49141
diff
changeset
|
99 |
let prefix = docket_name |
048f829a445a
hg-core: remove unneeded util now that we support Rust 1.42+
Raphaël Gomès <rgomes@octobus.net>
parents:
49141
diff
changeset
|
100 |
.strip_suffix(".n.a") |
048f829a445a
hg-core: remove unneeded util now that we support Rust 1.42+
Raphaël Gomès <rgomes@octobus.net>
parents:
49141
diff
changeset
|
101 |
.or_else(|| docket_name.strip_suffix(".n")) |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
102 |
.expect("expected docket path in .n or .n.a"); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
103 |
let name = format!("{}-{}.nd", prefix, uid); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
104 |
docket_path |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
105 |
.parent() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
106 |
.expect("expected a non-root path") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
107 |
.join(name) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
108 |
} |