Mercurial > public > mercurial-scm > hg-stable
annotate rust/hg-core/src/revlog/nodemap_docket.rs @ 46462:0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
This crate casts pointers to custom structs, with compile-time safety checks,
for easy and efficient binary data parsing.
See https://crates.io/crates/bytes-cast and
https://docs.rs/bytes-cast/0.1.0/bytes_cast/
Differential Revision: https://phab.mercurial-scm.org/D9788
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Fri, 15 Jan 2021 16:11:54 +0100 |
parents | 8a4914397d02 |
children | 43d63979a75e |
rev | line source |
---|---|
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
1 use bytes_cast::{unaligned, BytesCast}; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
2 use memmap::Mmap; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
3 use std::path::{Path, PathBuf}; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
4 |
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46091
diff
changeset
|
5 use super::revlog::RevlogError; |
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46091
diff
changeset
|
6 use crate::repo::Repo; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
7 use crate::utils::strip_suffix; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
8 |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
9 const ONDISK_VERSION: u8 = 1; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
10 |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
11 pub(super) struct NodeMapDocket { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
12 pub data_length: usize, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
13 // 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
|
14 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
15 |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
16 #[derive(BytesCast)] |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
17 #[repr(C)] |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
18 struct DocketHeader { |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
19 uid_size: u8, |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
20 _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
|
21 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
|
22 _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
|
23 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
|
24 } |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
25 |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
26 impl NodeMapDocket { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
27 /// 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
|
28 /// nodemap: |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
29 /// |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
30 /// * 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
|
31 /// small revlogs), or |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
32 /// * 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
|
33 /// 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
|
34 /// * 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
|
35 /// can happen in a rare race condition). |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
36 pub fn read_from_file( |
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46091
diff
changeset
|
37 repo: &Repo, |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
38 index_path: &Path, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
39 ) -> Result<Option<(Self, Mmap)>, RevlogError> { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
40 let docket_path = index_path.with_extension("n"); |
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46091
diff
changeset
|
41 let docket_bytes = match repo.store_vfs().read(&docket_path) { |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
42 Err(e) if e.kind() == std::io::ErrorKind::NotFound => { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
43 return Ok(None) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
44 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
45 Err(e) => return Err(RevlogError::IoError(e)), |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
46 Ok(bytes) => bytes, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
47 }; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
48 |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
49 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
|
50 docket_bytes.split_first() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
51 { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
52 rest |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
53 } else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
54 return Ok(None); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
55 }; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
56 |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
57 let (header, rest) = DocketHeader::from_bytes(input)?; |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
58 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
|
59 // 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
|
60 // systems? |
46462
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
61 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
|
62 let data_length = header.data_length.get() as usize; |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
63 let (uid, rest) = u8::slice_from_bytes(rest, uid_size)?; |
0800aa42bb4c
rust: use the bytes-cast crate to parse persistent nodemaps
Simon Sapin <simon.sapin@octobus.net>
parents:
46167
diff
changeset
|
64 let (_tip_node, _rest) = u8::slice_from_bytes(rest, tip_node_size)?; |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
65 let uid = |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
66 std::str::from_utf8(uid).map_err(|_| RevlogError::Corrupted)?; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
67 let docket = NodeMapDocket { data_length }; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
68 |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
69 let data_path = rawdata_path(&docket_path, uid); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
70 // TODO: use `std::fs::read` here when the `persistent-nodemap.mmap` |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
71 // config is false? |
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46091
diff
changeset
|
72 match repo.store_vfs().mmap_open(&data_path) { |
46091
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
73 Ok(mmap) => { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
74 if mmap.len() >= data_length { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
75 Ok(Some((docket, mmap))) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
76 } else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
77 Err(RevlogError::Corrupted) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
78 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
79 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
80 Err(error) => { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
81 if error.kind() == std::io::ErrorKind::NotFound { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
82 Ok(None) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
83 } else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
84 Err(RevlogError::IoError(error)) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
85 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
86 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
87 } |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
88 } |
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 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
|
92 let docket_name = docket_path |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
93 .file_name() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
94 .expect("expected a base name") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
95 .to_str() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
96 .expect("expected an ASCII file name in the store"); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
97 let prefix = strip_suffix(docket_name, ".n.a") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
98 .or_else(|| strip_suffix(docket_name, ".n")) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
99 .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
|
100 let name = format!("{}-{}.nd", prefix, uid); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
101 docket_path |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
102 .parent() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
103 .expect("expected a non-root path") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
104 .join(name) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
105 } |