annotate rust/hg-core/src/revlog/nodemap_docket.rs @ 46091:9eb07ab3f2d4

rhg: use persistent nodemap when available ? for node ID ? revision number lookups, instead on linear scan in a revlog. Differential Revision: https://phab.mercurial-scm.org/D9520
author Simon Sapin <simon-commits@exyr.org>
date Fri, 04 Dec 2020 17:27:10 +0100
parents
children 8a4914397d02
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
46091
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
1 use memmap::Mmap;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
2 use std::convert::TryInto;
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
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
5 use super::revlog::{mmap_open, RevlogError};
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
6 use crate::utils::strip_suffix;
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
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
15 impl NodeMapDocket {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
16 /// 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
17 /// nodemap:
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
18 ///
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
19 /// * 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
20 /// small revlogs), or
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
21 /// * 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
22 /// 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
23 /// * 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
24 /// can happen in a rare race condition).
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
25 pub fn read_from_file(
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
26 index_path: &Path,
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
27 ) -> Result<Option<(Self, Mmap)>, RevlogError> {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
28 let docket_path = index_path.with_extension("n");
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
29 let docket_bytes = match std::fs::read(&docket_path) {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
30 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
31 return Ok(None)
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
32 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
33 Err(e) => return Err(RevlogError::IoError(e)),
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
34 Ok(bytes) => bytes,
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
35 };
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
36
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
37 let mut input = if let Some((&ONDISK_VERSION, rest)) =
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
38 docket_bytes.split_first()
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
39 {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
40 rest
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
41 } else {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
42 return Ok(None);
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
43 };
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
44 let input = &mut input;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
45
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
46 let uid_size = read_u8(input)? as usize;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
47 let _tip_rev = read_be_u64(input)?;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
48 // 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
49 // systems?
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
50 let data_length = read_be_u64(input)? as usize;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
51 let _data_unused = read_be_u64(input)?;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
52 let tip_node_size = read_be_u64(input)? as usize;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
53 let uid = read_bytes(input, uid_size)?;
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
54 let _tip_node = read_bytes(input, tip_node_size)?;
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 let uid =
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
57 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
58 let docket = NodeMapDocket { data_length };
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
59
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
60 let data_path = rawdata_path(&docket_path, uid);
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
61 // 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
62 // config is false?
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
63 match mmap_open(&data_path) {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
64 Ok(mmap) => {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
65 if mmap.len() >= data_length {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
66 Ok(Some((docket, mmap)))
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
67 } else {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
68 Err(RevlogError::Corrupted)
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
69 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
70 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
71 Err(error) => {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
72 if error.kind() == std::io::ErrorKind::NotFound {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
73 Ok(None)
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
74 } else {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
75 Err(RevlogError::IoError(error))
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
76 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
77 }
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 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
81
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
82 fn read_bytes<'a>(
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
83 input: &mut &'a [u8],
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
84 count: usize,
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
85 ) -> Result<&'a [u8], RevlogError> {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
86 if let Some(start) = input.get(..count) {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
87 *input = &input[count..];
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
88 Ok(start)
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
89 } else {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
90 Err(RevlogError::Corrupted)
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
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
94 fn read_u8<'a>(input: &mut &[u8]) -> Result<u8, RevlogError> {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
95 Ok(read_bytes(input, 1)?[0])
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
96 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
97
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
98 fn read_be_u64<'a>(input: &mut &[u8]) -> Result<u64, RevlogError> {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
99 let array = read_bytes(input, std::mem::size_of::<u64>())?
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
100 .try_into()
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
101 .unwrap();
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
102 Ok(u64::from_be_bytes(array))
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
103 }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
104
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
105 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
106 let docket_name = docket_path
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
107 .file_name()
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
108 .expect("expected a base name")
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
109 .to_str()
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
110 .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
111 let prefix = strip_suffix(docket_name, ".n.a")
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
112 .or_else(|| strip_suffix(docket_name, ".n"))
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
113 .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
114 let name = format!("{}-{}.nd", prefix, uid);
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
115 docket_path
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
116 .parent()
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
117 .expect("expected a non-root path")
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
118 .join(name)
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff changeset
119 }