author | Simon Sapin <simon.sapin@octobus.net> |
Mon, 14 Dec 2020 16:33:15 +0100 | |
changeset 46167 | 8a4914397d02 |
parent 46090 | 9eb07ab3f2d4 |
child 46390 | 0800aa42bb4c |
permissions | -rw-r--r-- |
46090
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 |
|
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46090
diff
changeset
|
5 |
use super::revlog::RevlogError; |
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46090
diff
changeset
|
6 |
use crate::repo::Repo; |
46090
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 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
16 |
impl NodeMapDocket { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
17 |
/// 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
|
18 |
/// nodemap: |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
19 |
/// |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
20 |
/// * 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
|
21 |
/// small revlogs), or |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
22 |
/// * 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
|
23 |
/// 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
|
24 |
/// * 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
|
25 |
/// can happen in a rare race condition). |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
26 |
pub fn read_from_file( |
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46090
diff
changeset
|
27 |
repo: &Repo, |
46090
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
28 |
index_path: &Path, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
29 |
) -> Result<Option<(Self, Mmap)>, RevlogError> { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
30 |
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:
46090
diff
changeset
|
31 |
let docket_bytes = match repo.store_vfs().read(&docket_path) { |
46090
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
32 |
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
|
33 |
return Ok(None) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
34 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
35 |
Err(e) => return Err(RevlogError::IoError(e)), |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
36 |
Ok(bytes) => bytes, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
37 |
}; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
38 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
39 |
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
|
40 |
docket_bytes.split_first() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
41 |
{ |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
42 |
rest |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
43 |
} else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
44 |
return Ok(None); |
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 input = &mut input; |
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 |
let uid_size = read_u8(input)? as usize; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
49 |
let _tip_rev = read_be_u64(input)?; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
50 |
// 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
|
51 |
// systems? |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
52 |
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
|
53 |
let _data_unused = read_be_u64(input)?; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
54 |
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
|
55 |
let uid = read_bytes(input, uid_size)?; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
56 |
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
|
57 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
58 |
let uid = |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
59 |
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
|
60 |
let docket = NodeMapDocket { data_length }; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
61 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
62 |
let data_path = rawdata_path(&docket_path, uid); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
63 |
// 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
|
64 |
// config is false? |
46167
8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
46090
diff
changeset
|
65 |
match repo.store_vfs().mmap_open(&data_path) { |
46090
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
66 |
Ok(mmap) => { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
67 |
if mmap.len() >= data_length { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
68 |
Ok(Some((docket, mmap))) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
69 |
} else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
70 |
Err(RevlogError::Corrupted) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
71 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
72 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
73 |
Err(error) => { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
74 |
if error.kind() == std::io::ErrorKind::NotFound { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
75 |
Ok(None) |
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::IoError(error)) |
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 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
83 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
84 |
fn read_bytes<'a>( |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
85 |
input: &mut &'a [u8], |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
86 |
count: usize, |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
87 |
) -> Result<&'a [u8], RevlogError> { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
88 |
if let Some(start) = input.get(..count) { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
89 |
*input = &input[count..]; |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
90 |
Ok(start) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
91 |
} else { |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
92 |
Err(RevlogError::Corrupted) |
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 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
95 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
96 |
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
|
97 |
Ok(read_bytes(input, 1)?[0]) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
98 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
99 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
100 |
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
|
101 |
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
|
102 |
.try_into() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
103 |
.unwrap(); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
104 |
Ok(u64::from_be_bytes(array)) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
105 |
} |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
106 |
|
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
107 |
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
|
108 |
let docket_name = docket_path |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
109 |
.file_name() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
110 |
.expect("expected a base name") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
111 |
.to_str() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
112 |
.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
|
113 |
let prefix = strip_suffix(docket_name, ".n.a") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
114 |
.or_else(|| strip_suffix(docket_name, ".n")) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
115 |
.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
|
116 |
let name = format!("{}-{}.nd", prefix, uid); |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
117 |
docket_path |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
118 |
.parent() |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
119 |
.expect("expected a non-root path") |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
120 |
.join(name) |
9eb07ab3f2d4
rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents:
diff
changeset
|
121 |
} |