##// END OF EJS Templates
rust: Remove hex parsing from the nodemap...
Simon Sapin -
r47161:18a261b1 default
parent child Browse files
Show More
@@ -1,146 +1,146
1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 use clap::*;
6 use clap::*;
7 use hg::revlog::node::*;
7 use hg::revlog::node::*;
8 use hg::revlog::nodemap::*;
8 use hg::revlog::nodemap::*;
9 use hg::revlog::*;
9 use hg::revlog::*;
10 use memmap::MmapOptions;
10 use memmap::MmapOptions;
11 use rand::Rng;
11 use rand::Rng;
12 use std::fs::File;
12 use std::fs::File;
13 use std::io;
13 use std::io;
14 use std::io::Write;
14 use std::io::Write;
15 use std::path::{Path, PathBuf};
15 use std::path::{Path, PathBuf};
16 use std::str::FromStr;
16 use std::str::FromStr;
17 use std::time::Instant;
17 use std::time::Instant;
18
18
19 mod index;
19 mod index;
20 use index::Index;
20 use index::Index;
21
21
22 fn mmap_index(repo_path: &Path) -> Index {
22 fn mmap_index(repo_path: &Path) -> Index {
23 let mut path = PathBuf::from(repo_path);
23 let mut path = PathBuf::from(repo_path);
24 path.extend([".hg", "store", "00changelog.i"].iter());
24 path.extend([".hg", "store", "00changelog.i"].iter());
25 Index::load_mmap(path)
25 Index::load_mmap(path)
26 }
26 }
27
27
28 fn mmap_nodemap(path: &Path) -> NodeTree {
28 fn mmap_nodemap(path: &Path) -> NodeTree {
29 let file = File::open(path).unwrap();
29 let file = File::open(path).unwrap();
30 let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };
30 let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };
31 let len = mmap.len();
31 let len = mmap.len();
32 NodeTree::load_bytes(Box::new(mmap), len)
32 NodeTree::load_bytes(Box::new(mmap), len)
33 }
33 }
34
34
35 /// Scan the whole index and create the corresponding nodemap file at `path`
35 /// Scan the whole index and create the corresponding nodemap file at `path`
36 fn create(index: &Index, path: &Path) -> io::Result<()> {
36 fn create(index: &Index, path: &Path) -> io::Result<()> {
37 let mut file = File::create(path)?;
37 let mut file = File::create(path)?;
38 let start = Instant::now();
38 let start = Instant::now();
39 let mut nm = NodeTree::default();
39 let mut nm = NodeTree::default();
40 for rev in 0..index.len() {
40 for rev in 0..index.len() {
41 let rev = rev as Revision;
41 let rev = rev as Revision;
42 nm.insert(index, index.node(rev).unwrap(), rev).unwrap();
42 nm.insert(index, index.node(rev).unwrap(), rev).unwrap();
43 }
43 }
44 eprintln!("Nodemap constructed in RAM in {:?}", start.elapsed());
44 eprintln!("Nodemap constructed in RAM in {:?}", start.elapsed());
45 file.write(&nm.into_readonly_and_added_bytes().1)?;
45 file.write(&nm.into_readonly_and_added_bytes().1)?;
46 eprintln!("Nodemap written to disk");
46 eprintln!("Nodemap written to disk");
47 Ok(())
47 Ok(())
48 }
48 }
49
49
50 fn query(index: &Index, nm: &NodeTree, prefix: &str) {
50 fn query(index: &Index, nm: &NodeTree, prefix: &str) {
51 let start = Instant::now();
51 let start = Instant::now();
52 let res = nm.find_hex(index, prefix);
52 let res = NodePrefix::from_hex(prefix).map(|p| nm.find_bin(index, p));
53 println!("Result found in {:?}: {:?}", start.elapsed(), res);
53 println!("Result found in {:?}: {:?}", start.elapsed(), res);
54 }
54 }
55
55
56 fn bench(index: &Index, nm: &NodeTree, queries: usize) {
56 fn bench(index: &Index, nm: &NodeTree, queries: usize) {
57 let len = index.len() as u32;
57 let len = index.len() as u32;
58 let mut rng = rand::thread_rng();
58 let mut rng = rand::thread_rng();
59 let nodes: Vec<Node> = (0..queries)
59 let nodes: Vec<Node> = (0..queries)
60 .map(|_| {
60 .map(|_| {
61 index
61 index
62 .node((rng.gen::<u32>() % len) as Revision)
62 .node((rng.gen::<u32>() % len) as Revision)
63 .unwrap()
63 .unwrap()
64 .clone()
64 .clone()
65 })
65 })
66 .collect();
66 .collect();
67 if queries < 10 {
67 if queries < 10 {
68 let nodes_hex: Vec<String> =
68 let nodes_hex: Vec<String> =
69 nodes.iter().map(|n| format!("{:x}", n)).collect();
69 nodes.iter().map(|n| format!("{:x}", n)).collect();
70 println!("Nodes: {:?}", nodes_hex);
70 println!("Nodes: {:?}", nodes_hex);
71 }
71 }
72 let mut last: Option<Revision> = None;
72 let mut last: Option<Revision> = None;
73 let start = Instant::now();
73 let start = Instant::now();
74 for node in nodes.iter() {
74 for node in nodes.iter() {
75 last = nm.find_bin(index, node.into()).unwrap();
75 last = nm.find_bin(index, node.into()).unwrap();
76 }
76 }
77 let elapsed = start.elapsed();
77 let elapsed = start.elapsed();
78 println!(
78 println!(
79 "Did {} queries in {:?} (mean {:?}), last was {:x} with result {:?}",
79 "Did {} queries in {:?} (mean {:?}), last was {:x} with result {:?}",
80 queries,
80 queries,
81 elapsed,
81 elapsed,
82 elapsed / (queries as u32),
82 elapsed / (queries as u32),
83 nodes.last().unwrap(),
83 nodes.last().unwrap(),
84 last
84 last
85 );
85 );
86 }
86 }
87
87
88 fn main() {
88 fn main() {
89 let matches = App::new("Nodemap pure Rust example")
89 let matches = App::new("Nodemap pure Rust example")
90 .arg(
90 .arg(
91 Arg::with_name("REPOSITORY")
91 Arg::with_name("REPOSITORY")
92 .help("Path to the repository, always necessary for its index")
92 .help("Path to the repository, always necessary for its index")
93 .required(true),
93 .required(true),
94 )
94 )
95 .arg(
95 .arg(
96 Arg::with_name("NODEMAP_FILE")
96 Arg::with_name("NODEMAP_FILE")
97 .help("Path to the nodemap file, independent of REPOSITORY")
97 .help("Path to the nodemap file, independent of REPOSITORY")
98 .required(true),
98 .required(true),
99 )
99 )
100 .subcommand(
100 .subcommand(
101 SubCommand::with_name("create")
101 SubCommand::with_name("create")
102 .about("Create NODEMAP_FILE by scanning repository index"),
102 .about("Create NODEMAP_FILE by scanning repository index"),
103 )
103 )
104 .subcommand(
104 .subcommand(
105 SubCommand::with_name("query")
105 SubCommand::with_name("query")
106 .about("Query NODEMAP_FILE for PREFIX")
106 .about("Query NODEMAP_FILE for PREFIX")
107 .arg(Arg::with_name("PREFIX").required(true)),
107 .arg(Arg::with_name("PREFIX").required(true)),
108 )
108 )
109 .subcommand(
109 .subcommand(
110 SubCommand::with_name("bench")
110 SubCommand::with_name("bench")
111 .about(
111 .about(
112 "Perform #QUERIES random successful queries on NODEMAP_FILE")
112 "Perform #QUERIES random successful queries on NODEMAP_FILE")
113 .arg(Arg::with_name("QUERIES").required(true)),
113 .arg(Arg::with_name("QUERIES").required(true)),
114 )
114 )
115 .get_matches();
115 .get_matches();
116
116
117 let repo = matches.value_of("REPOSITORY").unwrap();
117 let repo = matches.value_of("REPOSITORY").unwrap();
118 let nm_path = matches.value_of("NODEMAP_FILE").unwrap();
118 let nm_path = matches.value_of("NODEMAP_FILE").unwrap();
119
119
120 let index = mmap_index(&Path::new(repo));
120 let index = mmap_index(&Path::new(repo));
121
121
122 if let Some(_) = matches.subcommand_matches("create") {
122 if let Some(_) = matches.subcommand_matches("create") {
123 println!("Creating nodemap file {} for repository {}", nm_path, repo);
123 println!("Creating nodemap file {} for repository {}", nm_path, repo);
124 create(&index, &Path::new(nm_path)).unwrap();
124 create(&index, &Path::new(nm_path)).unwrap();
125 return;
125 return;
126 }
126 }
127
127
128 let nm = mmap_nodemap(&Path::new(nm_path));
128 let nm = mmap_nodemap(&Path::new(nm_path));
129 if let Some(matches) = matches.subcommand_matches("query") {
129 if let Some(matches) = matches.subcommand_matches("query") {
130 let prefix = matches.value_of("PREFIX").unwrap();
130 let prefix = matches.value_of("PREFIX").unwrap();
131 println!(
131 println!(
132 "Querying {} in nodemap file {} of repository {}",
132 "Querying {} in nodemap file {} of repository {}",
133 prefix, nm_path, repo
133 prefix, nm_path, repo
134 );
134 );
135 query(&index, &nm, prefix);
135 query(&index, &nm, prefix);
136 }
136 }
137 if let Some(matches) = matches.subcommand_matches("bench") {
137 if let Some(matches) = matches.subcommand_matches("bench") {
138 let queries =
138 let queries =
139 usize::from_str(matches.value_of("QUERIES").unwrap()).unwrap();
139 usize::from_str(matches.value_of("QUERIES").unwrap()).unwrap();
140 println!(
140 println!(
141 "Doing {} random queries in nodemap file {} of repository {}",
141 "Doing {} random queries in nodemap file {} of repository {}",
142 queries, nm_path, repo
142 queries, nm_path, repo
143 );
143 );
144 bench(&index, &nm, queries);
144 bench(&index, &nm, queries);
145 }
145 }
146 }
146 }
@@ -1,1098 +1,1069
1 // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
1 // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
2 // and Mercurial contributors
2 // and Mercurial contributors
3 //
3 //
4 // This software may be used and distributed according to the terms of the
4 // This software may be used and distributed according to the terms of the
5 // GNU General Public License version 2 or any later version.
5 // GNU General Public License version 2 or any later version.
6 //! Indexing facilities for fast retrieval of `Revision` from `Node`
6 //! Indexing facilities for fast retrieval of `Revision` from `Node`
7 //!
7 //!
8 //! This provides a variation on the 16-ary radix tree that is
8 //! This provides a variation on the 16-ary radix tree that is
9 //! provided as "nodetree" in revlog.c, ready for append-only persistence
9 //! provided as "nodetree" in revlog.c, ready for append-only persistence
10 //! on disk.
10 //! on disk.
11 //!
11 //!
12 //! Following existing implicit conventions, the "nodemap" terminology
12 //! Following existing implicit conventions, the "nodemap" terminology
13 //! is used in a more abstract context.
13 //! is used in a more abstract context.
14
14
15 use super::{
15 use super::{
16 node::NULL_NODE, FromHexError, Node, NodePrefix, Revision, RevlogIndex,
16 node::NULL_NODE, Node, NodePrefix, Revision, RevlogIndex, NULL_REVISION,
17 NULL_REVISION,
18 };
17 };
19
18
20 use bytes_cast::{unaligned, BytesCast};
19 use bytes_cast::{unaligned, BytesCast};
21 use std::cmp::max;
20 use std::cmp::max;
22 use std::fmt;
21 use std::fmt;
23 use std::mem::{self, align_of, size_of};
22 use std::mem::{self, align_of, size_of};
24 use std::ops::Deref;
23 use std::ops::Deref;
25 use std::ops::Index;
24 use std::ops::Index;
26
25
27 #[derive(Debug, PartialEq)]
26 #[derive(Debug, PartialEq)]
28 pub enum NodeMapError {
27 pub enum NodeMapError {
29 MultipleResults,
28 MultipleResults,
30 InvalidNodePrefix,
31 /// A `Revision` stored in the nodemap could not be found in the index
29 /// A `Revision` stored in the nodemap could not be found in the index
32 RevisionNotInIndex(Revision),
30 RevisionNotInIndex(Revision),
33 }
31 }
34
32
35 impl From<FromHexError> for NodeMapError {
36 fn from(_: FromHexError) -> Self {
37 NodeMapError::InvalidNodePrefix
38 }
39 }
40
41 /// Mapping system from Mercurial nodes to revision numbers.
33 /// Mapping system from Mercurial nodes to revision numbers.
42 ///
34 ///
43 /// ## `RevlogIndex` and `NodeMap`
35 /// ## `RevlogIndex` and `NodeMap`
44 ///
36 ///
45 /// One way to think about their relationship is that
37 /// One way to think about their relationship is that
46 /// the `NodeMap` is a prefix-oriented reverse index of the `Node` information
38 /// the `NodeMap` is a prefix-oriented reverse index of the `Node` information
47 /// carried by a [`RevlogIndex`].
39 /// carried by a [`RevlogIndex`].
48 ///
40 ///
49 /// Many of the methods in this trait take a `RevlogIndex` argument
41 /// Many of the methods in this trait take a `RevlogIndex` argument
50 /// which is used for validation of their results. This index must naturally
42 /// which is used for validation of their results. This index must naturally
51 /// be the one the `NodeMap` is about, and it must be consistent.
43 /// be the one the `NodeMap` is about, and it must be consistent.
52 ///
44 ///
53 /// Notably, the `NodeMap` must not store
45 /// Notably, the `NodeMap` must not store
54 /// information about more `Revision` values than there are in the index.
46 /// information about more `Revision` values than there are in the index.
55 /// In these methods, an encountered `Revision` is not in the index, a
47 /// In these methods, an encountered `Revision` is not in the index, a
56 /// [`RevisionNotInIndex`] error is returned.
48 /// [`RevisionNotInIndex`] error is returned.
57 ///
49 ///
58 /// In insert operations, the rule is thus that the `NodeMap` must always
50 /// In insert operations, the rule is thus that the `NodeMap` must always
59 /// be updated after the `RevlogIndex`
51 /// be updated after the `RevlogIndex`
60 /// be updated first, and the `NodeMap` second.
52 /// be updated first, and the `NodeMap` second.
61 ///
53 ///
62 /// [`RevisionNotInIndex`]: enum.NodeMapError.html#variant.RevisionNotInIndex
54 /// [`RevisionNotInIndex`]: enum.NodeMapError.html#variant.RevisionNotInIndex
63 /// [`RevlogIndex`]: ../trait.RevlogIndex.html
55 /// [`RevlogIndex`]: ../trait.RevlogIndex.html
64 pub trait NodeMap {
56 pub trait NodeMap {
65 /// Find the unique `Revision` having the given `Node`
57 /// Find the unique `Revision` having the given `Node`
66 ///
58 ///
67 /// If no Revision matches the given `Node`, `Ok(None)` is returned.
59 /// If no Revision matches the given `Node`, `Ok(None)` is returned.
68 fn find_node(
60 fn find_node(
69 &self,
61 &self,
70 index: &impl RevlogIndex,
62 index: &impl RevlogIndex,
71 node: &Node,
63 node: &Node,
72 ) -> Result<Option<Revision>, NodeMapError> {
64 ) -> Result<Option<Revision>, NodeMapError> {
73 self.find_bin(index, node.into())
65 self.find_bin(index, node.into())
74 }
66 }
75
67
76 /// Find the unique Revision whose `Node` starts with a given binary prefix
68 /// Find the unique Revision whose `Node` starts with a given binary prefix
77 ///
69 ///
78 /// If no Revision matches the given prefix, `Ok(None)` is returned.
70 /// If no Revision matches the given prefix, `Ok(None)` is returned.
79 ///
71 ///
80 /// If several Revisions match the given prefix, a [`MultipleResults`]
72 /// If several Revisions match the given prefix, a [`MultipleResults`]
81 /// error is returned.
73 /// error is returned.
82 fn find_bin<'a>(
74 fn find_bin<'a>(
83 &self,
75 &self,
84 idx: &impl RevlogIndex,
76 idx: &impl RevlogIndex,
85 prefix: NodePrefix,
77 prefix: NodePrefix,
86 ) -> Result<Option<Revision>, NodeMapError>;
78 ) -> Result<Option<Revision>, NodeMapError>;
87
79
88 /// Find the unique Revision whose `Node` hexadecimal string representation
89 /// starts with a given prefix
90 ///
91 /// If no Revision matches the given prefix, `Ok(None)` is returned.
92 ///
93 /// If several Revisions match the given prefix, a [`MultipleResults`]
94 /// error is returned.
95 fn find_hex(
96 &self,
97 idx: &impl RevlogIndex,
98 prefix: &str,
99 ) -> Result<Option<Revision>, NodeMapError> {
100 self.find_bin(idx, NodePrefix::from_hex(prefix)?)
101 }
102
103 /// Give the size of the shortest node prefix that determines
80 /// Give the size of the shortest node prefix that determines
104 /// the revision uniquely.
81 /// the revision uniquely.
105 ///
82 ///
106 /// From a binary node prefix, if it is matched in the node map, this
83 /// From a binary node prefix, if it is matched in the node map, this
107 /// returns the number of hexadecimal digits that would had sufficed
84 /// returns the number of hexadecimal digits that would had sufficed
108 /// to find the revision uniquely.
85 /// to find the revision uniquely.
109 ///
86 ///
110 /// Returns `None` if no `Revision` could be found for the prefix.
87 /// Returns `None` if no `Revision` could be found for the prefix.
111 ///
88 ///
112 /// If several Revisions match the given prefix, a [`MultipleResults`]
89 /// If several Revisions match the given prefix, a [`MultipleResults`]
113 /// error is returned.
90 /// error is returned.
114 fn unique_prefix_len_bin<'a>(
91 fn unique_prefix_len_bin<'a>(
115 &self,
92 &self,
116 idx: &impl RevlogIndex,
93 idx: &impl RevlogIndex,
117 node_prefix: NodePrefix,
94 node_prefix: NodePrefix,
118 ) -> Result<Option<usize>, NodeMapError>;
95 ) -> Result<Option<usize>, NodeMapError>;
119
96
120 /// Same as `unique_prefix_len_bin`, with the hexadecimal representation
121 /// of the prefix as input.
122 fn unique_prefix_len_hex(
123 &self,
124 idx: &impl RevlogIndex,
125 prefix: &str,
126 ) -> Result<Option<usize>, NodeMapError> {
127 self.unique_prefix_len_bin(idx, NodePrefix::from_hex(prefix)?)
128 }
129
130 /// Same as `unique_prefix_len_bin`, with a full `Node` as input
97 /// Same as `unique_prefix_len_bin`, with a full `Node` as input
131 fn unique_prefix_len_node(
98 fn unique_prefix_len_node(
132 &self,
99 &self,
133 idx: &impl RevlogIndex,
100 idx: &impl RevlogIndex,
134 node: &Node,
101 node: &Node,
135 ) -> Result<Option<usize>, NodeMapError> {
102 ) -> Result<Option<usize>, NodeMapError> {
136 self.unique_prefix_len_bin(idx, node.into())
103 self.unique_prefix_len_bin(idx, node.into())
137 }
104 }
138 }
105 }
139
106
140 pub trait MutableNodeMap: NodeMap {
107 pub trait MutableNodeMap: NodeMap {
141 fn insert<I: RevlogIndex>(
108 fn insert<I: RevlogIndex>(
142 &mut self,
109 &mut self,
143 index: &I,
110 index: &I,
144 node: &Node,
111 node: &Node,
145 rev: Revision,
112 rev: Revision,
146 ) -> Result<(), NodeMapError>;
113 ) -> Result<(), NodeMapError>;
147 }
114 }
148
115
149 /// Low level NodeTree [`Blocks`] elements
116 /// Low level NodeTree [`Blocks`] elements
150 ///
117 ///
151 /// These are exactly as for instance on persistent storage.
118 /// These are exactly as for instance on persistent storage.
152 type RawElement = unaligned::I32Be;
119 type RawElement = unaligned::I32Be;
153
120
154 /// High level representation of values in NodeTree
121 /// High level representation of values in NodeTree
155 /// [`Blocks`](struct.Block.html)
122 /// [`Blocks`](struct.Block.html)
156 ///
123 ///
157 /// This is the high level representation that most algorithms should
124 /// This is the high level representation that most algorithms should
158 /// use.
125 /// use.
159 #[derive(Clone, Debug, Eq, PartialEq)]
126 #[derive(Clone, Debug, Eq, PartialEq)]
160 enum Element {
127 enum Element {
161 Rev(Revision),
128 Rev(Revision),
162 Block(usize),
129 Block(usize),
163 None,
130 None,
164 }
131 }
165
132
166 impl From<RawElement> for Element {
133 impl From<RawElement> for Element {
167 /// Conversion from low level representation, after endianness conversion.
134 /// Conversion from low level representation, after endianness conversion.
168 ///
135 ///
169 /// See [`Block`](struct.Block.html) for explanation about the encoding.
136 /// See [`Block`](struct.Block.html) for explanation about the encoding.
170 fn from(raw: RawElement) -> Element {
137 fn from(raw: RawElement) -> Element {
171 let int = raw.get();
138 let int = raw.get();
172 if int >= 0 {
139 if int >= 0 {
173 Element::Block(int as usize)
140 Element::Block(int as usize)
174 } else if int == -1 {
141 } else if int == -1 {
175 Element::None
142 Element::None
176 } else {
143 } else {
177 Element::Rev(-int - 2)
144 Element::Rev(-int - 2)
178 }
145 }
179 }
146 }
180 }
147 }
181
148
182 impl From<Element> for RawElement {
149 impl From<Element> for RawElement {
183 fn from(element: Element) -> RawElement {
150 fn from(element: Element) -> RawElement {
184 RawElement::from(match element {
151 RawElement::from(match element {
185 Element::None => 0,
152 Element::None => 0,
186 Element::Block(i) => i as i32,
153 Element::Block(i) => i as i32,
187 Element::Rev(rev) => -rev - 2,
154 Element::Rev(rev) => -rev - 2,
188 })
155 })
189 }
156 }
190 }
157 }
191
158
192 /// A logical block of the `NodeTree`, packed with a fixed size.
159 /// A logical block of the `NodeTree`, packed with a fixed size.
193 ///
160 ///
194 /// These are always used in container types implementing `Index<Block>`,
161 /// These are always used in container types implementing `Index<Block>`,
195 /// such as `&Block`
162 /// such as `&Block`
196 ///
163 ///
197 /// As an array of integers, its ith element encodes that the
164 /// As an array of integers, its ith element encodes that the
198 /// ith potential edge from the block, representing the ith hexadecimal digit
165 /// ith potential edge from the block, representing the ith hexadecimal digit
199 /// (nybble) `i` is either:
166 /// (nybble) `i` is either:
200 ///
167 ///
201 /// - absent (value -1)
168 /// - absent (value -1)
202 /// - another `Block` in the same indexable container (value β‰₯ 0)
169 /// - another `Block` in the same indexable container (value β‰₯ 0)
203 /// - a `Revision` leaf (value ≀ -2)
170 /// - a `Revision` leaf (value ≀ -2)
204 ///
171 ///
205 /// Endianness has to be fixed for consistency on shared storage across
172 /// Endianness has to be fixed for consistency on shared storage across
206 /// different architectures.
173 /// different architectures.
207 ///
174 ///
208 /// A key difference with the C `nodetree` is that we need to be
175 /// A key difference with the C `nodetree` is that we need to be
209 /// able to represent the [`Block`] at index 0, hence -1 is the empty marker
176 /// able to represent the [`Block`] at index 0, hence -1 is the empty marker
210 /// rather than 0 and the `Revision` range upper limit of -2 instead of -1.
177 /// rather than 0 and the `Revision` range upper limit of -2 instead of -1.
211 ///
178 ///
212 /// Another related difference is that `NULL_REVISION` (-1) is not
179 /// Another related difference is that `NULL_REVISION` (-1) is not
213 /// represented at all, because we want an immutable empty nodetree
180 /// represented at all, because we want an immutable empty nodetree
214 /// to be valid.
181 /// to be valid.
215
182
216 const ELEMENTS_PER_BLOCK: usize = 16; // number of different values in a nybble
183 const ELEMENTS_PER_BLOCK: usize = 16; // number of different values in a nybble
217
184
218 #[derive(Copy, Clone, BytesCast, PartialEq)]
185 #[derive(Copy, Clone, BytesCast, PartialEq)]
219 #[repr(transparent)]
186 #[repr(transparent)]
220 pub struct Block([RawElement; ELEMENTS_PER_BLOCK]);
187 pub struct Block([RawElement; ELEMENTS_PER_BLOCK]);
221
188
222 impl Block {
189 impl Block {
223 fn new() -> Self {
190 fn new() -> Self {
224 let absent_node = RawElement::from(-1);
191 let absent_node = RawElement::from(-1);
225 Block([absent_node; ELEMENTS_PER_BLOCK])
192 Block([absent_node; ELEMENTS_PER_BLOCK])
226 }
193 }
227
194
228 fn get(&self, nybble: u8) -> Element {
195 fn get(&self, nybble: u8) -> Element {
229 self.0[nybble as usize].into()
196 self.0[nybble as usize].into()
230 }
197 }
231
198
232 fn set(&mut self, nybble: u8, element: Element) {
199 fn set(&mut self, nybble: u8, element: Element) {
233 self.0[nybble as usize] = element.into()
200 self.0[nybble as usize] = element.into()
234 }
201 }
235 }
202 }
236
203
237 impl fmt::Debug for Block {
204 impl fmt::Debug for Block {
238 /// sparse representation for testing and debugging purposes
205 /// sparse representation for testing and debugging purposes
239 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240 f.debug_map()
207 f.debug_map()
241 .entries((0..16).filter_map(|i| match self.get(i) {
208 .entries((0..16).filter_map(|i| match self.get(i) {
242 Element::None => None,
209 Element::None => None,
243 element => Some((i, element)),
210 element => Some((i, element)),
244 }))
211 }))
245 .finish()
212 .finish()
246 }
213 }
247 }
214 }
248
215
249 /// A mutable 16-radix tree with the root block logically at the end
216 /// A mutable 16-radix tree with the root block logically at the end
250 ///
217 ///
251 /// Because of the append only nature of our node trees, we need to
218 /// Because of the append only nature of our node trees, we need to
252 /// keep the original untouched and store new blocks separately.
219 /// keep the original untouched and store new blocks separately.
253 ///
220 ///
254 /// The mutable root `Block` is kept apart so that we don't have to rebump
221 /// The mutable root `Block` is kept apart so that we don't have to rebump
255 /// it on each insertion.
222 /// it on each insertion.
256 pub struct NodeTree {
223 pub struct NodeTree {
257 readonly: Box<dyn Deref<Target = [Block]> + Send>,
224 readonly: Box<dyn Deref<Target = [Block]> + Send>,
258 growable: Vec<Block>,
225 growable: Vec<Block>,
259 root: Block,
226 root: Block,
260 masked_inner_blocks: usize,
227 masked_inner_blocks: usize,
261 }
228 }
262
229
263 impl Index<usize> for NodeTree {
230 impl Index<usize> for NodeTree {
264 type Output = Block;
231 type Output = Block;
265
232
266 fn index(&self, i: usize) -> &Block {
233 fn index(&self, i: usize) -> &Block {
267 let ro_len = self.readonly.len();
234 let ro_len = self.readonly.len();
268 if i < ro_len {
235 if i < ro_len {
269 &self.readonly[i]
236 &self.readonly[i]
270 } else if i == ro_len + self.growable.len() {
237 } else if i == ro_len + self.growable.len() {
271 &self.root
238 &self.root
272 } else {
239 } else {
273 &self.growable[i - ro_len]
240 &self.growable[i - ro_len]
274 }
241 }
275 }
242 }
276 }
243 }
277
244
278 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
245 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
279 fn has_prefix_or_none(
246 fn has_prefix_or_none(
280 idx: &impl RevlogIndex,
247 idx: &impl RevlogIndex,
281 prefix: NodePrefix,
248 prefix: NodePrefix,
282 rev: Revision,
249 rev: Revision,
283 ) -> Result<Option<Revision>, NodeMapError> {
250 ) -> Result<Option<Revision>, NodeMapError> {
284 idx.node(rev)
251 idx.node(rev)
285 .ok_or_else(|| NodeMapError::RevisionNotInIndex(rev))
252 .ok_or_else(|| NodeMapError::RevisionNotInIndex(rev))
286 .map(|node| {
253 .map(|node| {
287 if prefix.is_prefix_of(node) {
254 if prefix.is_prefix_of(node) {
288 Some(rev)
255 Some(rev)
289 } else {
256 } else {
290 None
257 None
291 }
258 }
292 })
259 })
293 }
260 }
294
261
295 /// validate that the candidate's node starts indeed with given prefix,
262 /// validate that the candidate's node starts indeed with given prefix,
296 /// and treat ambiguities related to `NULL_REVISION`.
263 /// and treat ambiguities related to `NULL_REVISION`.
297 ///
264 ///
298 /// From the data in the NodeTree, one can only conclude that some
265 /// From the data in the NodeTree, one can only conclude that some
299 /// revision is the only one for a *subprefix* of the one being looked up.
266 /// revision is the only one for a *subprefix* of the one being looked up.
300 fn validate_candidate(
267 fn validate_candidate(
301 idx: &impl RevlogIndex,
268 idx: &impl RevlogIndex,
302 prefix: NodePrefix,
269 prefix: NodePrefix,
303 candidate: (Option<Revision>, usize),
270 candidate: (Option<Revision>, usize),
304 ) -> Result<(Option<Revision>, usize), NodeMapError> {
271 ) -> Result<(Option<Revision>, usize), NodeMapError> {
305 let (rev, steps) = candidate;
272 let (rev, steps) = candidate;
306 if let Some(nz_nybble) = prefix.first_different_nybble(&NULL_NODE) {
273 if let Some(nz_nybble) = prefix.first_different_nybble(&NULL_NODE) {
307 rev.map_or(Ok((None, steps)), |r| {
274 rev.map_or(Ok((None, steps)), |r| {
308 has_prefix_or_none(idx, prefix, r)
275 has_prefix_or_none(idx, prefix, r)
309 .map(|opt| (opt, max(steps, nz_nybble + 1)))
276 .map(|opt| (opt, max(steps, nz_nybble + 1)))
310 })
277 })
311 } else {
278 } else {
312 // the prefix is only made of zeros; NULL_REVISION always matches it
279 // the prefix is only made of zeros; NULL_REVISION always matches it
313 // and any other *valid* result is an ambiguity
280 // and any other *valid* result is an ambiguity
314 match rev {
281 match rev {
315 None => Ok((Some(NULL_REVISION), steps + 1)),
282 None => Ok((Some(NULL_REVISION), steps + 1)),
316 Some(r) => match has_prefix_or_none(idx, prefix, r)? {
283 Some(r) => match has_prefix_or_none(idx, prefix, r)? {
317 None => Ok((Some(NULL_REVISION), steps + 1)),
284 None => Ok((Some(NULL_REVISION), steps + 1)),
318 _ => Err(NodeMapError::MultipleResults),
285 _ => Err(NodeMapError::MultipleResults),
319 },
286 },
320 }
287 }
321 }
288 }
322 }
289 }
323
290
324 impl NodeTree {
291 impl NodeTree {
325 /// Initiate a NodeTree from an immutable slice-like of `Block`
292 /// Initiate a NodeTree from an immutable slice-like of `Block`
326 ///
293 ///
327 /// We keep `readonly` and clone its root block if it isn't empty.
294 /// We keep `readonly` and clone its root block if it isn't empty.
328 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self {
295 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self {
329 let root = readonly.last().cloned().unwrap_or_else(Block::new);
296 let root = readonly.last().cloned().unwrap_or_else(Block::new);
330 NodeTree {
297 NodeTree {
331 readonly,
298 readonly,
332 growable: Vec::new(),
299 growable: Vec::new(),
333 root,
300 root,
334 masked_inner_blocks: 0,
301 masked_inner_blocks: 0,
335 }
302 }
336 }
303 }
337
304
338 /// Create from an opaque bunch of bytes
305 /// Create from an opaque bunch of bytes
339 ///
306 ///
340 /// The created `NodeTreeBytes` from `buffer`,
307 /// The created `NodeTreeBytes` from `buffer`,
341 /// of which exactly `amount` bytes are used.
308 /// of which exactly `amount` bytes are used.
342 ///
309 ///
343 /// - `buffer` could be derived from `PyBuffer` and `Mmap` objects.
310 /// - `buffer` could be derived from `PyBuffer` and `Mmap` objects.
344 /// - `offset` allows for the final file format to include fixed data
311 /// - `offset` allows for the final file format to include fixed data
345 /// (generation number, behavioural flags)
312 /// (generation number, behavioural flags)
346 /// - `amount` is expressed in bytes, and is not automatically derived from
313 /// - `amount` is expressed in bytes, and is not automatically derived from
347 /// `bytes`, so that a caller that manages them atomically can perform
314 /// `bytes`, so that a caller that manages them atomically can perform
348 /// temporary disk serializations and still rollback easily if needed.
315 /// temporary disk serializations and still rollback easily if needed.
349 /// First use-case for this would be to support Mercurial shell hooks.
316 /// First use-case for this would be to support Mercurial shell hooks.
350 ///
317 ///
351 /// panics if `buffer` is smaller than `amount`
318 /// panics if `buffer` is smaller than `amount`
352 pub fn load_bytes(
319 pub fn load_bytes(
353 bytes: Box<dyn Deref<Target = [u8]> + Send>,
320 bytes: Box<dyn Deref<Target = [u8]> + Send>,
354 amount: usize,
321 amount: usize,
355 ) -> Self {
322 ) -> Self {
356 NodeTree::new(Box::new(NodeTreeBytes::new(bytes, amount)))
323 NodeTree::new(Box::new(NodeTreeBytes::new(bytes, amount)))
357 }
324 }
358
325
359 /// Retrieve added `Block` and the original immutable data
326 /// Retrieve added `Block` and the original immutable data
360 pub fn into_readonly_and_added(
327 pub fn into_readonly_and_added(
361 self,
328 self,
362 ) -> (Box<dyn Deref<Target = [Block]> + Send>, Vec<Block>) {
329 ) -> (Box<dyn Deref<Target = [Block]> + Send>, Vec<Block>) {
363 let mut vec = self.growable;
330 let mut vec = self.growable;
364 let readonly = self.readonly;
331 let readonly = self.readonly;
365 if readonly.last() != Some(&self.root) {
332 if readonly.last() != Some(&self.root) {
366 vec.push(self.root);
333 vec.push(self.root);
367 }
334 }
368 (readonly, vec)
335 (readonly, vec)
369 }
336 }
370
337
371 /// Retrieve added `Blocks` as bytes, ready to be written to persistent
338 /// Retrieve added `Blocks` as bytes, ready to be written to persistent
372 /// storage
339 /// storage
373 pub fn into_readonly_and_added_bytes(
340 pub fn into_readonly_and_added_bytes(
374 self,
341 self,
375 ) -> (Box<dyn Deref<Target = [Block]> + Send>, Vec<u8>) {
342 ) -> (Box<dyn Deref<Target = [Block]> + Send>, Vec<u8>) {
376 let (readonly, vec) = self.into_readonly_and_added();
343 let (readonly, vec) = self.into_readonly_and_added();
377 // Prevent running `v`'s destructor so we are in complete control
344 // Prevent running `v`'s destructor so we are in complete control
378 // of the allocation.
345 // of the allocation.
379 let vec = mem::ManuallyDrop::new(vec);
346 let vec = mem::ManuallyDrop::new(vec);
380
347
381 // Transmute the `Vec<Block>` to a `Vec<u8>`. Blocks are contiguous
348 // Transmute the `Vec<Block>` to a `Vec<u8>`. Blocks are contiguous
382 // bytes, so this is perfectly safe.
349 // bytes, so this is perfectly safe.
383 let bytes = unsafe {
350 let bytes = unsafe {
384 // Check for compatible allocation layout.
351 // Check for compatible allocation layout.
385 // (Optimized away by constant-folding + dead code elimination.)
352 // (Optimized away by constant-folding + dead code elimination.)
386 assert_eq!(size_of::<Block>(), 64);
353 assert_eq!(size_of::<Block>(), 64);
387 assert_eq!(align_of::<Block>(), 1);
354 assert_eq!(align_of::<Block>(), 1);
388
355
389 // /!\ Any use of `vec` after this is use-after-free.
356 // /!\ Any use of `vec` after this is use-after-free.
390 // TODO: use `into_raw_parts` once stabilized
357 // TODO: use `into_raw_parts` once stabilized
391 Vec::from_raw_parts(
358 Vec::from_raw_parts(
392 vec.as_ptr() as *mut u8,
359 vec.as_ptr() as *mut u8,
393 vec.len() * size_of::<Block>(),
360 vec.len() * size_of::<Block>(),
394 vec.capacity() * size_of::<Block>(),
361 vec.capacity() * size_of::<Block>(),
395 )
362 )
396 };
363 };
397 (readonly, bytes)
364 (readonly, bytes)
398 }
365 }
399
366
400 /// Total number of blocks
367 /// Total number of blocks
401 fn len(&self) -> usize {
368 fn len(&self) -> usize {
402 self.readonly.len() + self.growable.len() + 1
369 self.readonly.len() + self.growable.len() + 1
403 }
370 }
404
371
405 /// Implemented for completeness
372 /// Implemented for completeness
406 ///
373 ///
407 /// A `NodeTree` always has at least the mutable root block.
374 /// A `NodeTree` always has at least the mutable root block.
408 #[allow(dead_code)]
375 #[allow(dead_code)]
409 fn is_empty(&self) -> bool {
376 fn is_empty(&self) -> bool {
410 false
377 false
411 }
378 }
412
379
413 /// Main working method for `NodeTree` searches
380 /// Main working method for `NodeTree` searches
414 ///
381 ///
415 /// The first returned value is the result of analysing `NodeTree` data
382 /// The first returned value is the result of analysing `NodeTree` data
416 /// *alone*: whereas `None` guarantees that the given prefix is absent
383 /// *alone*: whereas `None` guarantees that the given prefix is absent
417 /// from the `NodeTree` data (but still could match `NULL_NODE`), with
384 /// from the `NodeTree` data (but still could match `NULL_NODE`), with
418 /// `Some(rev)`, it is to be understood that `rev` is the unique `Revision`
385 /// `Some(rev)`, it is to be understood that `rev` is the unique `Revision`
419 /// that could match the prefix. Actually, all that can be inferred from
386 /// that could match the prefix. Actually, all that can be inferred from
420 /// the `NodeTree` data is that `rev` is the revision with the longest
387 /// the `NodeTree` data is that `rev` is the revision with the longest
421 /// common node prefix with the given prefix.
388 /// common node prefix with the given prefix.
422 ///
389 ///
423 /// The second returned value is the size of the smallest subprefix
390 /// The second returned value is the size of the smallest subprefix
424 /// of `prefix` that would give the same result, i.e. not the
391 /// of `prefix` that would give the same result, i.e. not the
425 /// `MultipleResults` error variant (again, using only the data of the
392 /// `MultipleResults` error variant (again, using only the data of the
426 /// `NodeTree`).
393 /// `NodeTree`).
427 fn lookup(
394 fn lookup(
428 &self,
395 &self,
429 prefix: NodePrefix,
396 prefix: NodePrefix,
430 ) -> Result<(Option<Revision>, usize), NodeMapError> {
397 ) -> Result<(Option<Revision>, usize), NodeMapError> {
431 for (i, visit_item) in self.visit(prefix).enumerate() {
398 for (i, visit_item) in self.visit(prefix).enumerate() {
432 if let Some(opt) = visit_item.final_revision() {
399 if let Some(opt) = visit_item.final_revision() {
433 return Ok((opt, i + 1));
400 return Ok((opt, i + 1));
434 }
401 }
435 }
402 }
436 Err(NodeMapError::MultipleResults)
403 Err(NodeMapError::MultipleResults)
437 }
404 }
438
405
439 fn visit<'n>(&'n self, prefix: NodePrefix) -> NodeTreeVisitor<'n> {
406 fn visit<'n>(&'n self, prefix: NodePrefix) -> NodeTreeVisitor<'n> {
440 NodeTreeVisitor {
407 NodeTreeVisitor {
441 nt: self,
408 nt: self,
442 prefix,
409 prefix,
443 visit: self.len() - 1,
410 visit: self.len() - 1,
444 nybble_idx: 0,
411 nybble_idx: 0,
445 done: false,
412 done: false,
446 }
413 }
447 }
414 }
448 /// Return a mutable reference for `Block` at index `idx`.
415 /// Return a mutable reference for `Block` at index `idx`.
449 ///
416 ///
450 /// If `idx` lies in the immutable area, then the reference is to
417 /// If `idx` lies in the immutable area, then the reference is to
451 /// a newly appended copy.
418 /// a newly appended copy.
452 ///
419 ///
453 /// Returns (new_idx, glen, mut_ref) where
420 /// Returns (new_idx, glen, mut_ref) where
454 ///
421 ///
455 /// - `new_idx` is the index of the mutable `Block`
422 /// - `new_idx` is the index of the mutable `Block`
456 /// - `mut_ref` is a mutable reference to the mutable Block.
423 /// - `mut_ref` is a mutable reference to the mutable Block.
457 /// - `glen` is the new length of `self.growable`
424 /// - `glen` is the new length of `self.growable`
458 ///
425 ///
459 /// Note: the caller wouldn't be allowed to query `self.growable.len()`
426 /// Note: the caller wouldn't be allowed to query `self.growable.len()`
460 /// itself because of the mutable borrow taken with the returned `Block`
427 /// itself because of the mutable borrow taken with the returned `Block`
461 fn mutable_block(&mut self, idx: usize) -> (usize, &mut Block, usize) {
428 fn mutable_block(&mut self, idx: usize) -> (usize, &mut Block, usize) {
462 let ro_blocks = &self.readonly;
429 let ro_blocks = &self.readonly;
463 let ro_len = ro_blocks.len();
430 let ro_len = ro_blocks.len();
464 let glen = self.growable.len();
431 let glen = self.growable.len();
465 if idx < ro_len {
432 if idx < ro_len {
466 self.masked_inner_blocks += 1;
433 self.masked_inner_blocks += 1;
467 self.growable.push(ro_blocks[idx]);
434 self.growable.push(ro_blocks[idx]);
468 (glen + ro_len, &mut self.growable[glen], glen + 1)
435 (glen + ro_len, &mut self.growable[glen], glen + 1)
469 } else if glen + ro_len == idx {
436 } else if glen + ro_len == idx {
470 (idx, &mut self.root, glen)
437 (idx, &mut self.root, glen)
471 } else {
438 } else {
472 (idx, &mut self.growable[idx - ro_len], glen)
439 (idx, &mut self.growable[idx - ro_len], glen)
473 }
440 }
474 }
441 }
475
442
476 /// Main insertion method
443 /// Main insertion method
477 ///
444 ///
478 /// This will dive in the node tree to find the deepest `Block` for
445 /// This will dive in the node tree to find the deepest `Block` for
479 /// `node`, split it as much as needed and record `node` in there.
446 /// `node`, split it as much as needed and record `node` in there.
480 /// The method then backtracks, updating references in all the visited
447 /// The method then backtracks, updating references in all the visited
481 /// blocks from the root.
448 /// blocks from the root.
482 ///
449 ///
483 /// All the mutated `Block` are copied first to the growable part if
450 /// All the mutated `Block` are copied first to the growable part if
484 /// needed. That happens for those in the immutable part except the root.
451 /// needed. That happens for those in the immutable part except the root.
485 pub fn insert<I: RevlogIndex>(
452 pub fn insert<I: RevlogIndex>(
486 &mut self,
453 &mut self,
487 index: &I,
454 index: &I,
488 node: &Node,
455 node: &Node,
489 rev: Revision,
456 rev: Revision,
490 ) -> Result<(), NodeMapError> {
457 ) -> Result<(), NodeMapError> {
491 let ro_len = &self.readonly.len();
458 let ro_len = &self.readonly.len();
492
459
493 let mut visit_steps: Vec<_> = self.visit(node.into()).collect();
460 let mut visit_steps: Vec<_> = self.visit(node.into()).collect();
494 let read_nybbles = visit_steps.len();
461 let read_nybbles = visit_steps.len();
495 // visit_steps cannot be empty, since we always visit the root block
462 // visit_steps cannot be empty, since we always visit the root block
496 let deepest = visit_steps.pop().unwrap();
463 let deepest = visit_steps.pop().unwrap();
497
464
498 let (mut block_idx, mut block, mut glen) =
465 let (mut block_idx, mut block, mut glen) =
499 self.mutable_block(deepest.block_idx);
466 self.mutable_block(deepest.block_idx);
500
467
501 if let Element::Rev(old_rev) = deepest.element {
468 if let Element::Rev(old_rev) = deepest.element {
502 let old_node = index
469 let old_node = index
503 .node(old_rev)
470 .node(old_rev)
504 .ok_or_else(|| NodeMapError::RevisionNotInIndex(old_rev))?;
471 .ok_or_else(|| NodeMapError::RevisionNotInIndex(old_rev))?;
505 if old_node == node {
472 if old_node == node {
506 return Ok(()); // avoid creating lots of useless blocks
473 return Ok(()); // avoid creating lots of useless blocks
507 }
474 }
508
475
509 // Looping over the tail of nybbles in both nodes, creating
476 // Looping over the tail of nybbles in both nodes, creating
510 // new blocks until we find the difference
477 // new blocks until we find the difference
511 let mut new_block_idx = ro_len + glen;
478 let mut new_block_idx = ro_len + glen;
512 let mut nybble = deepest.nybble;
479 let mut nybble = deepest.nybble;
513 for nybble_pos in read_nybbles..node.nybbles_len() {
480 for nybble_pos in read_nybbles..node.nybbles_len() {
514 block.set(nybble, Element::Block(new_block_idx));
481 block.set(nybble, Element::Block(new_block_idx));
515
482
516 let new_nybble = node.get_nybble(nybble_pos);
483 let new_nybble = node.get_nybble(nybble_pos);
517 let old_nybble = old_node.get_nybble(nybble_pos);
484 let old_nybble = old_node.get_nybble(nybble_pos);
518
485
519 if old_nybble == new_nybble {
486 if old_nybble == new_nybble {
520 self.growable.push(Block::new());
487 self.growable.push(Block::new());
521 block = &mut self.growable[glen];
488 block = &mut self.growable[glen];
522 glen += 1;
489 glen += 1;
523 new_block_idx += 1;
490 new_block_idx += 1;
524 nybble = new_nybble;
491 nybble = new_nybble;
525 } else {
492 } else {
526 let mut new_block = Block::new();
493 let mut new_block = Block::new();
527 new_block.set(old_nybble, Element::Rev(old_rev));
494 new_block.set(old_nybble, Element::Rev(old_rev));
528 new_block.set(new_nybble, Element::Rev(rev));
495 new_block.set(new_nybble, Element::Rev(rev));
529 self.growable.push(new_block);
496 self.growable.push(new_block);
530 break;
497 break;
531 }
498 }
532 }
499 }
533 } else {
500 } else {
534 // Free slot in the deepest block: no splitting has to be done
501 // Free slot in the deepest block: no splitting has to be done
535 block.set(deepest.nybble, Element::Rev(rev));
502 block.set(deepest.nybble, Element::Rev(rev));
536 }
503 }
537
504
538 // Backtrack over visit steps to update references
505 // Backtrack over visit steps to update references
539 while let Some(visited) = visit_steps.pop() {
506 while let Some(visited) = visit_steps.pop() {
540 let to_write = Element::Block(block_idx);
507 let to_write = Element::Block(block_idx);
541 if visit_steps.is_empty() {
508 if visit_steps.is_empty() {
542 self.root.set(visited.nybble, to_write);
509 self.root.set(visited.nybble, to_write);
543 break;
510 break;
544 }
511 }
545 let (new_idx, block, _) = self.mutable_block(visited.block_idx);
512 let (new_idx, block, _) = self.mutable_block(visited.block_idx);
546 if block.get(visited.nybble) == to_write {
513 if block.get(visited.nybble) == to_write {
547 break;
514 break;
548 }
515 }
549 block.set(visited.nybble, to_write);
516 block.set(visited.nybble, to_write);
550 block_idx = new_idx;
517 block_idx = new_idx;
551 }
518 }
552 Ok(())
519 Ok(())
553 }
520 }
554
521
555 /// Make the whole `NodeTree` logically empty, without touching the
522 /// Make the whole `NodeTree` logically empty, without touching the
556 /// immutable part.
523 /// immutable part.
557 pub fn invalidate_all(&mut self) {
524 pub fn invalidate_all(&mut self) {
558 self.root = Block::new();
525 self.root = Block::new();
559 self.growable = Vec::new();
526 self.growable = Vec::new();
560 self.masked_inner_blocks = self.readonly.len();
527 self.masked_inner_blocks = self.readonly.len();
561 }
528 }
562
529
563 /// Return the number of blocks in the readonly part that are currently
530 /// Return the number of blocks in the readonly part that are currently
564 /// masked in the mutable part.
531 /// masked in the mutable part.
565 ///
532 ///
566 /// The `NodeTree` structure has no efficient way to know how many blocks
533 /// The `NodeTree` structure has no efficient way to know how many blocks
567 /// are already unreachable in the readonly part.
534 /// are already unreachable in the readonly part.
568 ///
535 ///
569 /// After a call to `invalidate_all()`, the returned number can be actually
536 /// After a call to `invalidate_all()`, the returned number can be actually
570 /// bigger than the whole readonly part, a conventional way to mean that
537 /// bigger than the whole readonly part, a conventional way to mean that
571 /// all the readonly blocks have been masked. This is what is really
538 /// all the readonly blocks have been masked. This is what is really
572 /// useful to the caller and does not require to know how many were
539 /// useful to the caller and does not require to know how many were
573 /// actually unreachable to begin with.
540 /// actually unreachable to begin with.
574 pub fn masked_readonly_blocks(&self) -> usize {
541 pub fn masked_readonly_blocks(&self) -> usize {
575 if let Some(readonly_root) = self.readonly.last() {
542 if let Some(readonly_root) = self.readonly.last() {
576 if readonly_root == &self.root {
543 if readonly_root == &self.root {
577 return 0;
544 return 0;
578 }
545 }
579 } else {
546 } else {
580 return 0;
547 return 0;
581 }
548 }
582 self.masked_inner_blocks + 1
549 self.masked_inner_blocks + 1
583 }
550 }
584 }
551 }
585
552
586 pub struct NodeTreeBytes {
553 pub struct NodeTreeBytes {
587 buffer: Box<dyn Deref<Target = [u8]> + Send>,
554 buffer: Box<dyn Deref<Target = [u8]> + Send>,
588 len_in_blocks: usize,
555 len_in_blocks: usize,
589 }
556 }
590
557
591 impl NodeTreeBytes {
558 impl NodeTreeBytes {
592 fn new(
559 fn new(
593 buffer: Box<dyn Deref<Target = [u8]> + Send>,
560 buffer: Box<dyn Deref<Target = [u8]> + Send>,
594 amount: usize,
561 amount: usize,
595 ) -> Self {
562 ) -> Self {
596 assert!(buffer.len() >= amount);
563 assert!(buffer.len() >= amount);
597 let len_in_blocks = amount / size_of::<Block>();
564 let len_in_blocks = amount / size_of::<Block>();
598 NodeTreeBytes {
565 NodeTreeBytes {
599 buffer,
566 buffer,
600 len_in_blocks,
567 len_in_blocks,
601 }
568 }
602 }
569 }
603 }
570 }
604
571
605 impl Deref for NodeTreeBytes {
572 impl Deref for NodeTreeBytes {
606 type Target = [Block];
573 type Target = [Block];
607
574
608 fn deref(&self) -> &[Block] {
575 fn deref(&self) -> &[Block] {
609 Block::slice_from_bytes(&self.buffer, self.len_in_blocks)
576 Block::slice_from_bytes(&self.buffer, self.len_in_blocks)
610 // `NodeTreeBytes::new` already asserted that `self.buffer` is
577 // `NodeTreeBytes::new` already asserted that `self.buffer` is
611 // large enough.
578 // large enough.
612 .unwrap()
579 .unwrap()
613 .0
580 .0
614 }
581 }
615 }
582 }
616
583
617 struct NodeTreeVisitor<'n> {
584 struct NodeTreeVisitor<'n> {
618 nt: &'n NodeTree,
585 nt: &'n NodeTree,
619 prefix: NodePrefix,
586 prefix: NodePrefix,
620 visit: usize,
587 visit: usize,
621 nybble_idx: usize,
588 nybble_idx: usize,
622 done: bool,
589 done: bool,
623 }
590 }
624
591
625 #[derive(Debug, PartialEq, Clone)]
592 #[derive(Debug, PartialEq, Clone)]
626 struct NodeTreeVisitItem {
593 struct NodeTreeVisitItem {
627 block_idx: usize,
594 block_idx: usize,
628 nybble: u8,
595 nybble: u8,
629 element: Element,
596 element: Element,
630 }
597 }
631
598
632 impl<'n> Iterator for NodeTreeVisitor<'n> {
599 impl<'n> Iterator for NodeTreeVisitor<'n> {
633 type Item = NodeTreeVisitItem;
600 type Item = NodeTreeVisitItem;
634
601
635 fn next(&mut self) -> Option<Self::Item> {
602 fn next(&mut self) -> Option<Self::Item> {
636 if self.done || self.nybble_idx >= self.prefix.nybbles_len() {
603 if self.done || self.nybble_idx >= self.prefix.nybbles_len() {
637 return None;
604 return None;
638 }
605 }
639
606
640 let nybble = self.prefix.get_nybble(self.nybble_idx);
607 let nybble = self.prefix.get_nybble(self.nybble_idx);
641 self.nybble_idx += 1;
608 self.nybble_idx += 1;
642
609
643 let visit = self.visit;
610 let visit = self.visit;
644 let element = self.nt[visit].get(nybble);
611 let element = self.nt[visit].get(nybble);
645 if let Element::Block(idx) = element {
612 if let Element::Block(idx) = element {
646 self.visit = idx;
613 self.visit = idx;
647 } else {
614 } else {
648 self.done = true;
615 self.done = true;
649 }
616 }
650
617
651 Some(NodeTreeVisitItem {
618 Some(NodeTreeVisitItem {
652 block_idx: visit,
619 block_idx: visit,
653 nybble,
620 nybble,
654 element,
621 element,
655 })
622 })
656 }
623 }
657 }
624 }
658
625
659 impl NodeTreeVisitItem {
626 impl NodeTreeVisitItem {
660 // Return `Some(opt)` if this item is final, with `opt` being the
627 // Return `Some(opt)` if this item is final, with `opt` being the
661 // `Revision` that it may represent.
628 // `Revision` that it may represent.
662 //
629 //
663 // If the item is not terminal, return `None`
630 // If the item is not terminal, return `None`
664 fn final_revision(&self) -> Option<Option<Revision>> {
631 fn final_revision(&self) -> Option<Option<Revision>> {
665 match self.element {
632 match self.element {
666 Element::Block(_) => None,
633 Element::Block(_) => None,
667 Element::Rev(r) => Some(Some(r)),
634 Element::Rev(r) => Some(Some(r)),
668 Element::None => Some(None),
635 Element::None => Some(None),
669 }
636 }
670 }
637 }
671 }
638 }
672
639
673 impl From<Vec<Block>> for NodeTree {
640 impl From<Vec<Block>> for NodeTree {
674 fn from(vec: Vec<Block>) -> Self {
641 fn from(vec: Vec<Block>) -> Self {
675 Self::new(Box::new(vec))
642 Self::new(Box::new(vec))
676 }
643 }
677 }
644 }
678
645
679 impl fmt::Debug for NodeTree {
646 impl fmt::Debug for NodeTree {
680 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
681 let readonly: &[Block] = &*self.readonly;
648 let readonly: &[Block] = &*self.readonly;
682 write!(
649 write!(
683 f,
650 f,
684 "readonly: {:?}, growable: {:?}, root: {:?}",
651 "readonly: {:?}, growable: {:?}, root: {:?}",
685 readonly, self.growable, self.root
652 readonly, self.growable, self.root
686 )
653 )
687 }
654 }
688 }
655 }
689
656
690 impl Default for NodeTree {
657 impl Default for NodeTree {
691 /// Create a fully mutable empty NodeTree
658 /// Create a fully mutable empty NodeTree
692 fn default() -> Self {
659 fn default() -> Self {
693 NodeTree::new(Box::new(Vec::new()))
660 NodeTree::new(Box::new(Vec::new()))
694 }
661 }
695 }
662 }
696
663
697 impl NodeMap for NodeTree {
664 impl NodeMap for NodeTree {
698 fn find_bin<'a>(
665 fn find_bin<'a>(
699 &self,
666 &self,
700 idx: &impl RevlogIndex,
667 idx: &impl RevlogIndex,
701 prefix: NodePrefix,
668 prefix: NodePrefix,
702 ) -> Result<Option<Revision>, NodeMapError> {
669 ) -> Result<Option<Revision>, NodeMapError> {
703 validate_candidate(idx, prefix, self.lookup(prefix)?)
670 validate_candidate(idx, prefix, self.lookup(prefix)?)
704 .map(|(opt, _shortest)| opt)
671 .map(|(opt, _shortest)| opt)
705 }
672 }
706
673
707 fn unique_prefix_len_bin<'a>(
674 fn unique_prefix_len_bin<'a>(
708 &self,
675 &self,
709 idx: &impl RevlogIndex,
676 idx: &impl RevlogIndex,
710 prefix: NodePrefix,
677 prefix: NodePrefix,
711 ) -> Result<Option<usize>, NodeMapError> {
678 ) -> Result<Option<usize>, NodeMapError> {
712 validate_candidate(idx, prefix, self.lookup(prefix)?)
679 validate_candidate(idx, prefix, self.lookup(prefix)?)
713 .map(|(opt, shortest)| opt.map(|_rev| shortest))
680 .map(|(opt, shortest)| opt.map(|_rev| shortest))
714 }
681 }
715 }
682 }
716
683
717 #[cfg(test)]
684 #[cfg(test)]
718 mod tests {
685 mod tests {
719 use super::NodeMapError::*;
686 use super::NodeMapError::*;
720 use super::*;
687 use super::*;
721 use crate::revlog::node::{hex_pad_right, Node};
688 use crate::revlog::node::{hex_pad_right, Node};
722 use std::collections::HashMap;
689 use std::collections::HashMap;
723
690
724 /// Creates a `Block` using a syntax close to the `Debug` output
691 /// Creates a `Block` using a syntax close to the `Debug` output
725 macro_rules! block {
692 macro_rules! block {
726 {$($nybble:tt : $variant:ident($val:tt)),*} => (
693 {$($nybble:tt : $variant:ident($val:tt)),*} => (
727 {
694 {
728 let mut block = Block::new();
695 let mut block = Block::new();
729 $(block.set($nybble, Element::$variant($val)));*;
696 $(block.set($nybble, Element::$variant($val)));*;
730 block
697 block
731 }
698 }
732 )
699 )
733 }
700 }
734
701
735 #[test]
702 #[test]
736 fn test_block_debug() {
703 fn test_block_debug() {
737 let mut block = Block::new();
704 let mut block = Block::new();
738 block.set(1, Element::Rev(3));
705 block.set(1, Element::Rev(3));
739 block.set(10, Element::Block(0));
706 block.set(10, Element::Block(0));
740 assert_eq!(format!("{:?}", block), "{1: Rev(3), 10: Block(0)}");
707 assert_eq!(format!("{:?}", block), "{1: Rev(3), 10: Block(0)}");
741 }
708 }
742
709
743 #[test]
710 #[test]
744 fn test_block_macro() {
711 fn test_block_macro() {
745 let block = block! {5: Block(2)};
712 let block = block! {5: Block(2)};
746 assert_eq!(format!("{:?}", block), "{5: Block(2)}");
713 assert_eq!(format!("{:?}", block), "{5: Block(2)}");
747
714
748 let block = block! {13: Rev(15), 5: Block(2)};
715 let block = block! {13: Rev(15), 5: Block(2)};
749 assert_eq!(format!("{:?}", block), "{5: Block(2), 13: Rev(15)}");
716 assert_eq!(format!("{:?}", block), "{5: Block(2), 13: Rev(15)}");
750 }
717 }
751
718
752 #[test]
719 #[test]
753 fn test_raw_block() {
720 fn test_raw_block() {
754 let mut raw = [255u8; 64];
721 let mut raw = [255u8; 64];
755
722
756 let mut counter = 0;
723 let mut counter = 0;
757 for val in [0_i32, 15, -2, -1, -3].iter() {
724 for val in [0_i32, 15, -2, -1, -3].iter() {
758 for byte in val.to_be_bytes().iter() {
725 for byte in val.to_be_bytes().iter() {
759 raw[counter] = *byte;
726 raw[counter] = *byte;
760 counter += 1;
727 counter += 1;
761 }
728 }
762 }
729 }
763 let (block, _) = Block::from_bytes(&raw).unwrap();
730 let (block, _) = Block::from_bytes(&raw).unwrap();
764 assert_eq!(block.get(0), Element::Block(0));
731 assert_eq!(block.get(0), Element::Block(0));
765 assert_eq!(block.get(1), Element::Block(15));
732 assert_eq!(block.get(1), Element::Block(15));
766 assert_eq!(block.get(3), Element::None);
733 assert_eq!(block.get(3), Element::None);
767 assert_eq!(block.get(2), Element::Rev(0));
734 assert_eq!(block.get(2), Element::Rev(0));
768 assert_eq!(block.get(4), Element::Rev(1));
735 assert_eq!(block.get(4), Element::Rev(1));
769 }
736 }
770
737
771 type TestIndex = HashMap<Revision, Node>;
738 type TestIndex = HashMap<Revision, Node>;
772
739
773 impl RevlogIndex for TestIndex {
740 impl RevlogIndex for TestIndex {
774 fn node(&self, rev: Revision) -> Option<&Node> {
741 fn node(&self, rev: Revision) -> Option<&Node> {
775 self.get(&rev)
742 self.get(&rev)
776 }
743 }
777
744
778 fn len(&self) -> usize {
745 fn len(&self) -> usize {
779 self.len()
746 self.len()
780 }
747 }
781 }
748 }
782
749
783 /// Pad hexadecimal Node prefix with zeros on the right
750 /// Pad hexadecimal Node prefix with zeros on the right
784 ///
751 ///
785 /// This avoids having to repeatedly write very long hexadecimal
752 /// This avoids having to repeatedly write very long hexadecimal
786 /// strings for test data, and brings actual hash size independency.
753 /// strings for test data, and brings actual hash size independency.
787 #[cfg(test)]
754 #[cfg(test)]
788 fn pad_node(hex: &str) -> Node {
755 fn pad_node(hex: &str) -> Node {
789 Node::from_hex(&hex_pad_right(hex)).unwrap()
756 Node::from_hex(&hex_pad_right(hex)).unwrap()
790 }
757 }
791
758
792 /// Pad hexadecimal Node prefix with zeros on the right, then insert
759 /// Pad hexadecimal Node prefix with zeros on the right, then insert
793 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
760 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
794 idx.insert(rev, pad_node(hex));
761 idx.insert(rev, pad_node(hex));
795 }
762 }
796
763
797 fn sample_nodetree() -> NodeTree {
764 fn sample_nodetree() -> NodeTree {
798 NodeTree::from(vec![
765 NodeTree::from(vec![
799 block![0: Rev(9)],
766 block![0: Rev(9)],
800 block![0: Rev(0), 1: Rev(9)],
767 block![0: Rev(0), 1: Rev(9)],
801 block![0: Block(1), 1:Rev(1)],
768 block![0: Block(1), 1:Rev(1)],
802 ])
769 ])
803 }
770 }
804
771
772 fn hex(s: &str) -> NodePrefix {
773 NodePrefix::from_hex(s).unwrap()
774 }
775
805 #[test]
776 #[test]
806 fn test_nt_debug() {
777 fn test_nt_debug() {
807 let nt = sample_nodetree();
778 let nt = sample_nodetree();
808 assert_eq!(
779 assert_eq!(
809 format!("{:?}", nt),
780 format!("{:?}", nt),
810 "readonly: \
781 "readonly: \
811 [{0: Rev(9)}, {0: Rev(0), 1: Rev(9)}, {0: Block(1), 1: Rev(1)}], \
782 [{0: Rev(9)}, {0: Rev(0), 1: Rev(9)}, {0: Block(1), 1: Rev(1)}], \
812 growable: [], \
783 growable: [], \
813 root: {0: Block(1), 1: Rev(1)}",
784 root: {0: Block(1), 1: Rev(1)}",
814 );
785 );
815 }
786 }
816
787
817 #[test]
788 #[test]
818 fn test_immutable_find_simplest() -> Result<(), NodeMapError> {
789 fn test_immutable_find_simplest() -> Result<(), NodeMapError> {
819 let mut idx: TestIndex = HashMap::new();
790 let mut idx: TestIndex = HashMap::new();
820 pad_insert(&mut idx, 1, "1234deadcafe");
791 pad_insert(&mut idx, 1, "1234deadcafe");
821
792
822 let nt = NodeTree::from(vec![block! {1: Rev(1)}]);
793 let nt = NodeTree::from(vec![block! {1: Rev(1)}]);
823 assert_eq!(nt.find_hex(&idx, "1")?, Some(1));
794 assert_eq!(nt.find_bin(&idx, hex("1"))?, Some(1));
824 assert_eq!(nt.find_hex(&idx, "12")?, Some(1));
795 assert_eq!(nt.find_bin(&idx, hex("12"))?, Some(1));
825 assert_eq!(nt.find_hex(&idx, "1234de")?, Some(1));
796 assert_eq!(nt.find_bin(&idx, hex("1234de"))?, Some(1));
826 assert_eq!(nt.find_hex(&idx, "1a")?, None);
797 assert_eq!(nt.find_bin(&idx, hex("1a"))?, None);
827 assert_eq!(nt.find_hex(&idx, "ab")?, None);
798 assert_eq!(nt.find_bin(&idx, hex("ab"))?, None);
828
799
829 // and with full binary Nodes
800 // and with full binary Nodes
830 assert_eq!(nt.find_node(&idx, idx.get(&1).unwrap())?, Some(1));
801 assert_eq!(nt.find_node(&idx, idx.get(&1).unwrap())?, Some(1));
831 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
802 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
832 assert_eq!(nt.find_node(&idx, &unknown)?, None);
803 assert_eq!(nt.find_node(&idx, &unknown)?, None);
833 Ok(())
804 Ok(())
834 }
805 }
835
806
836 #[test]
807 #[test]
837 fn test_immutable_find_one_jump() {
808 fn test_immutable_find_one_jump() {
838 let mut idx = TestIndex::new();
809 let mut idx = TestIndex::new();
839 pad_insert(&mut idx, 9, "012");
810 pad_insert(&mut idx, 9, "012");
840 pad_insert(&mut idx, 0, "00a");
811 pad_insert(&mut idx, 0, "00a");
841
812
842 let nt = sample_nodetree();
813 let nt = sample_nodetree();
843
814
844 assert_eq!(nt.find_hex(&idx, "0"), Err(MultipleResults));
815 assert_eq!(nt.find_bin(&idx, hex("0")), Err(MultipleResults));
845 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
816 assert_eq!(nt.find_bin(&idx, hex("01")), Ok(Some(9)));
846 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
817 assert_eq!(nt.find_bin(&idx, hex("00")), Err(MultipleResults));
847 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
818 assert_eq!(nt.find_bin(&idx, hex("00a")), Ok(Some(0)));
848 assert_eq!(nt.unique_prefix_len_hex(&idx, "00a"), Ok(Some(3)));
819 assert_eq!(nt.unique_prefix_len_bin(&idx, hex("00a")), Ok(Some(3)));
849 assert_eq!(nt.find_hex(&idx, "000"), Ok(Some(NULL_REVISION)));
820 assert_eq!(nt.find_bin(&idx, hex("000")), Ok(Some(NULL_REVISION)));
850 }
821 }
851
822
852 #[test]
823 #[test]
853 fn test_mutated_find() -> Result<(), NodeMapError> {
824 fn test_mutated_find() -> Result<(), NodeMapError> {
854 let mut idx = TestIndex::new();
825 let mut idx = TestIndex::new();
855 pad_insert(&mut idx, 9, "012");
826 pad_insert(&mut idx, 9, "012");
856 pad_insert(&mut idx, 0, "00a");
827 pad_insert(&mut idx, 0, "00a");
857 pad_insert(&mut idx, 2, "cafe");
828 pad_insert(&mut idx, 2, "cafe");
858 pad_insert(&mut idx, 3, "15");
829 pad_insert(&mut idx, 3, "15");
859 pad_insert(&mut idx, 1, "10");
830 pad_insert(&mut idx, 1, "10");
860
831
861 let nt = NodeTree {
832 let nt = NodeTree {
862 readonly: sample_nodetree().readonly,
833 readonly: sample_nodetree().readonly,
863 growable: vec![block![0: Rev(1), 5: Rev(3)]],
834 growable: vec![block![0: Rev(1), 5: Rev(3)]],
864 root: block![0: Block(1), 1:Block(3), 12: Rev(2)],
835 root: block![0: Block(1), 1:Block(3), 12: Rev(2)],
865 masked_inner_blocks: 1,
836 masked_inner_blocks: 1,
866 };
837 };
867 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
838 assert_eq!(nt.find_bin(&idx, hex("10"))?, Some(1));
868 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
839 assert_eq!(nt.find_bin(&idx, hex("c"))?, Some(2));
869 assert_eq!(nt.unique_prefix_len_hex(&idx, "c")?, Some(1));
840 assert_eq!(nt.unique_prefix_len_bin(&idx, hex("c"))?, Some(1));
870 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
841 assert_eq!(nt.find_bin(&idx, hex("00")), Err(MultipleResults));
871 assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION));
842 assert_eq!(nt.find_bin(&idx, hex("000"))?, Some(NULL_REVISION));
872 assert_eq!(nt.unique_prefix_len_hex(&idx, "000")?, Some(3));
843 assert_eq!(nt.unique_prefix_len_bin(&idx, hex("000"))?, Some(3));
873 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
844 assert_eq!(nt.find_bin(&idx, hex("01"))?, Some(9));
874 assert_eq!(nt.masked_readonly_blocks(), 2);
845 assert_eq!(nt.masked_readonly_blocks(), 2);
875 Ok(())
846 Ok(())
876 }
847 }
877
848
878 struct TestNtIndex {
849 struct TestNtIndex {
879 index: TestIndex,
850 index: TestIndex,
880 nt: NodeTree,
851 nt: NodeTree,
881 }
852 }
882
853
883 impl TestNtIndex {
854 impl TestNtIndex {
884 fn new() -> Self {
855 fn new() -> Self {
885 TestNtIndex {
856 TestNtIndex {
886 index: HashMap::new(),
857 index: HashMap::new(),
887 nt: NodeTree::default(),
858 nt: NodeTree::default(),
888 }
859 }
889 }
860 }
890
861
891 fn insert(
862 fn insert(
892 &mut self,
863 &mut self,
893 rev: Revision,
864 rev: Revision,
894 hex: &str,
865 hex: &str,
895 ) -> Result<(), NodeMapError> {
866 ) -> Result<(), NodeMapError> {
896 let node = pad_node(hex);
867 let node = pad_node(hex);
897 self.index.insert(rev, node.clone());
868 self.index.insert(rev, node.clone());
898 self.nt.insert(&self.index, &node, rev)?;
869 self.nt.insert(&self.index, &node, rev)?;
899 Ok(())
870 Ok(())
900 }
871 }
901
872
902 fn find_hex(
873 fn find_hex(
903 &self,
874 &self,
904 prefix: &str,
875 prefix: &str,
905 ) -> Result<Option<Revision>, NodeMapError> {
876 ) -> Result<Option<Revision>, NodeMapError> {
906 self.nt.find_hex(&self.index, prefix)
877 self.nt.find_bin(&self.index, hex(prefix))
907 }
878 }
908
879
909 fn unique_prefix_len_hex(
880 fn unique_prefix_len_hex(
910 &self,
881 &self,
911 prefix: &str,
882 prefix: &str,
912 ) -> Result<Option<usize>, NodeMapError> {
883 ) -> Result<Option<usize>, NodeMapError> {
913 self.nt.unique_prefix_len_hex(&self.index, prefix)
884 self.nt.unique_prefix_len_bin(&self.index, hex(prefix))
914 }
885 }
915
886
916 /// Drain `added` and restart a new one
887 /// Drain `added` and restart a new one
917 fn commit(self) -> Self {
888 fn commit(self) -> Self {
918 let mut as_vec: Vec<Block> =
889 let mut as_vec: Vec<Block> =
919 self.nt.readonly.iter().map(|block| block.clone()).collect();
890 self.nt.readonly.iter().map(|block| block.clone()).collect();
920 as_vec.extend(self.nt.growable);
891 as_vec.extend(self.nt.growable);
921 as_vec.push(self.nt.root);
892 as_vec.push(self.nt.root);
922
893
923 Self {
894 Self {
924 index: self.index,
895 index: self.index,
925 nt: NodeTree::from(as_vec).into(),
896 nt: NodeTree::from(as_vec).into(),
926 }
897 }
927 }
898 }
928 }
899 }
929
900
930 #[test]
901 #[test]
931 fn test_insert_full_mutable() -> Result<(), NodeMapError> {
902 fn test_insert_full_mutable() -> Result<(), NodeMapError> {
932 let mut idx = TestNtIndex::new();
903 let mut idx = TestNtIndex::new();
933 idx.insert(0, "1234")?;
904 idx.insert(0, "1234")?;
934 assert_eq!(idx.find_hex("1")?, Some(0));
905 assert_eq!(idx.find_hex("1")?, Some(0));
935 assert_eq!(idx.find_hex("12")?, Some(0));
906 assert_eq!(idx.find_hex("12")?, Some(0));
936
907
937 // let's trigger a simple split
908 // let's trigger a simple split
938 idx.insert(1, "1a34")?;
909 idx.insert(1, "1a34")?;
939 assert_eq!(idx.nt.growable.len(), 1);
910 assert_eq!(idx.nt.growable.len(), 1);
940 assert_eq!(idx.find_hex("12")?, Some(0));
911 assert_eq!(idx.find_hex("12")?, Some(0));
941 assert_eq!(idx.find_hex("1a")?, Some(1));
912 assert_eq!(idx.find_hex("1a")?, Some(1));
942
913
943 // reinserting is a no_op
914 // reinserting is a no_op
944 idx.insert(1, "1a34")?;
915 idx.insert(1, "1a34")?;
945 assert_eq!(idx.nt.growable.len(), 1);
916 assert_eq!(idx.nt.growable.len(), 1);
946 assert_eq!(idx.find_hex("12")?, Some(0));
917 assert_eq!(idx.find_hex("12")?, Some(0));
947 assert_eq!(idx.find_hex("1a")?, Some(1));
918 assert_eq!(idx.find_hex("1a")?, Some(1));
948
919
949 idx.insert(2, "1a01")?;
920 idx.insert(2, "1a01")?;
950 assert_eq!(idx.nt.growable.len(), 2);
921 assert_eq!(idx.nt.growable.len(), 2);
951 assert_eq!(idx.find_hex("1a"), Err(NodeMapError::MultipleResults));
922 assert_eq!(idx.find_hex("1a"), Err(NodeMapError::MultipleResults));
952 assert_eq!(idx.find_hex("12")?, Some(0));
923 assert_eq!(idx.find_hex("12")?, Some(0));
953 assert_eq!(idx.find_hex("1a3")?, Some(1));
924 assert_eq!(idx.find_hex("1a3")?, Some(1));
954 assert_eq!(idx.find_hex("1a0")?, Some(2));
925 assert_eq!(idx.find_hex("1a0")?, Some(2));
955 assert_eq!(idx.find_hex("1a12")?, None);
926 assert_eq!(idx.find_hex("1a12")?, None);
956
927
957 // now let's make it split and create more than one additional block
928 // now let's make it split and create more than one additional block
958 idx.insert(3, "1a345")?;
929 idx.insert(3, "1a345")?;
959 assert_eq!(idx.nt.growable.len(), 4);
930 assert_eq!(idx.nt.growable.len(), 4);
960 assert_eq!(idx.find_hex("1a340")?, Some(1));
931 assert_eq!(idx.find_hex("1a340")?, Some(1));
961 assert_eq!(idx.find_hex("1a345")?, Some(3));
932 assert_eq!(idx.find_hex("1a345")?, Some(3));
962 assert_eq!(idx.find_hex("1a341")?, None);
933 assert_eq!(idx.find_hex("1a341")?, None);
963
934
964 // there's no readonly block to mask
935 // there's no readonly block to mask
965 assert_eq!(idx.nt.masked_readonly_blocks(), 0);
936 assert_eq!(idx.nt.masked_readonly_blocks(), 0);
966 Ok(())
937 Ok(())
967 }
938 }
968
939
969 #[test]
940 #[test]
970 fn test_unique_prefix_len_zero_prefix() {
941 fn test_unique_prefix_len_zero_prefix() {
971 let mut idx = TestNtIndex::new();
942 let mut idx = TestNtIndex::new();
972 idx.insert(0, "00000abcd").unwrap();
943 idx.insert(0, "00000abcd").unwrap();
973
944
974 assert_eq!(idx.find_hex("000"), Err(NodeMapError::MultipleResults));
945 assert_eq!(idx.find_hex("000"), Err(NodeMapError::MultipleResults));
975 // in the nodetree proper, this will be found at the first nybble
946 // in the nodetree proper, this will be found at the first nybble
976 // yet the correct answer for unique_prefix_len is not 1, nor 1+1,
947 // yet the correct answer for unique_prefix_len is not 1, nor 1+1,
977 // but the first difference with `NULL_NODE`
948 // but the first difference with `NULL_NODE`
978 assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6)));
949 assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6)));
979 assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6)));
950 assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6)));
980
951
981 // same with odd result
952 // same with odd result
982 idx.insert(1, "00123").unwrap();
953 idx.insert(1, "00123").unwrap();
983 assert_eq!(idx.unique_prefix_len_hex("001"), Ok(Some(3)));
954 assert_eq!(idx.unique_prefix_len_hex("001"), Ok(Some(3)));
984 assert_eq!(idx.unique_prefix_len_hex("0012"), Ok(Some(3)));
955 assert_eq!(idx.unique_prefix_len_hex("0012"), Ok(Some(3)));
985
956
986 // these are unchanged of course
957 // these are unchanged of course
987 assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6)));
958 assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6)));
988 assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6)));
959 assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6)));
989 }
960 }
990
961
991 #[test]
962 #[test]
992 fn test_insert_extreme_splitting() -> Result<(), NodeMapError> {
963 fn test_insert_extreme_splitting() -> Result<(), NodeMapError> {
993 // check that the splitting loop is long enough
964 // check that the splitting loop is long enough
994 let mut nt_idx = TestNtIndex::new();
965 let mut nt_idx = TestNtIndex::new();
995 let nt = &mut nt_idx.nt;
966 let nt = &mut nt_idx.nt;
996 let idx = &mut nt_idx.index;
967 let idx = &mut nt_idx.index;
997
968
998 let node0_hex = hex_pad_right("444444");
969 let node0_hex = hex_pad_right("444444");
999 let mut node1_hex = hex_pad_right("444444").clone();
970 let mut node1_hex = hex_pad_right("444444").clone();
1000 node1_hex.pop();
971 node1_hex.pop();
1001 node1_hex.push('5');
972 node1_hex.push('5');
1002 let node0 = Node::from_hex(&node0_hex).unwrap();
973 let node0 = Node::from_hex(&node0_hex).unwrap();
1003 let node1 = Node::from_hex(&node1_hex).unwrap();
974 let node1 = Node::from_hex(&node1_hex).unwrap();
1004
975
1005 idx.insert(0, node0.clone());
976 idx.insert(0, node0.clone());
1006 nt.insert(idx, &node0, 0)?;
977 nt.insert(idx, &node0, 0)?;
1007 idx.insert(1, node1.clone());
978 idx.insert(1, node1.clone());
1008 nt.insert(idx, &node1, 1)?;
979 nt.insert(idx, &node1, 1)?;
1009
980
1010 assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0));
981 assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0));
1011 assert_eq!(nt.find_bin(idx, (&node1).into())?, Some(1));
982 assert_eq!(nt.find_bin(idx, (&node1).into())?, Some(1));
1012 Ok(())
983 Ok(())
1013 }
984 }
1014
985
1015 #[test]
986 #[test]
1016 fn test_insert_partly_immutable() -> Result<(), NodeMapError> {
987 fn test_insert_partly_immutable() -> Result<(), NodeMapError> {
1017 let mut idx = TestNtIndex::new();
988 let mut idx = TestNtIndex::new();
1018 idx.insert(0, "1234")?;
989 idx.insert(0, "1234")?;
1019 idx.insert(1, "1235")?;
990 idx.insert(1, "1235")?;
1020 idx.insert(2, "131")?;
991 idx.insert(2, "131")?;
1021 idx.insert(3, "cafe")?;
992 idx.insert(3, "cafe")?;
1022 let mut idx = idx.commit();
993 let mut idx = idx.commit();
1023 assert_eq!(idx.find_hex("1234")?, Some(0));
994 assert_eq!(idx.find_hex("1234")?, Some(0));
1024 assert_eq!(idx.find_hex("1235")?, Some(1));
995 assert_eq!(idx.find_hex("1235")?, Some(1));
1025 assert_eq!(idx.find_hex("131")?, Some(2));
996 assert_eq!(idx.find_hex("131")?, Some(2));
1026 assert_eq!(idx.find_hex("cafe")?, Some(3));
997 assert_eq!(idx.find_hex("cafe")?, Some(3));
1027 // we did not add anything since init from readonly
998 // we did not add anything since init from readonly
1028 assert_eq!(idx.nt.masked_readonly_blocks(), 0);
999 assert_eq!(idx.nt.masked_readonly_blocks(), 0);
1029
1000
1030 idx.insert(4, "123A")?;
1001 idx.insert(4, "123A")?;
1031 assert_eq!(idx.find_hex("1234")?, Some(0));
1002 assert_eq!(idx.find_hex("1234")?, Some(0));
1032 assert_eq!(idx.find_hex("1235")?, Some(1));
1003 assert_eq!(idx.find_hex("1235")?, Some(1));
1033 assert_eq!(idx.find_hex("131")?, Some(2));
1004 assert_eq!(idx.find_hex("131")?, Some(2));
1034 assert_eq!(idx.find_hex("cafe")?, Some(3));
1005 assert_eq!(idx.find_hex("cafe")?, Some(3));
1035 assert_eq!(idx.find_hex("123A")?, Some(4));
1006 assert_eq!(idx.find_hex("123A")?, Some(4));
1036 // we masked blocks for all prefixes of "123", including the root
1007 // we masked blocks for all prefixes of "123", including the root
1037 assert_eq!(idx.nt.masked_readonly_blocks(), 4);
1008 assert_eq!(idx.nt.masked_readonly_blocks(), 4);
1038
1009
1039 eprintln!("{:?}", idx.nt);
1010 eprintln!("{:?}", idx.nt);
1040 idx.insert(5, "c0")?;
1011 idx.insert(5, "c0")?;
1041 assert_eq!(idx.find_hex("cafe")?, Some(3));
1012 assert_eq!(idx.find_hex("cafe")?, Some(3));
1042 assert_eq!(idx.find_hex("c0")?, Some(5));
1013 assert_eq!(idx.find_hex("c0")?, Some(5));
1043 assert_eq!(idx.find_hex("c1")?, None);
1014 assert_eq!(idx.find_hex("c1")?, None);
1044 assert_eq!(idx.find_hex("1234")?, Some(0));
1015 assert_eq!(idx.find_hex("1234")?, Some(0));
1045 // inserting "c0" is just splitting the 'c' slot of the mutable root,
1016 // inserting "c0" is just splitting the 'c' slot of the mutable root,
1046 // it doesn't mask anything
1017 // it doesn't mask anything
1047 assert_eq!(idx.nt.masked_readonly_blocks(), 4);
1018 assert_eq!(idx.nt.masked_readonly_blocks(), 4);
1048
1019
1049 Ok(())
1020 Ok(())
1050 }
1021 }
1051
1022
1052 #[test]
1023 #[test]
1053 fn test_invalidate_all() -> Result<(), NodeMapError> {
1024 fn test_invalidate_all() -> Result<(), NodeMapError> {
1054 let mut idx = TestNtIndex::new();
1025 let mut idx = TestNtIndex::new();
1055 idx.insert(0, "1234")?;
1026 idx.insert(0, "1234")?;
1056 idx.insert(1, "1235")?;
1027 idx.insert(1, "1235")?;
1057 idx.insert(2, "131")?;
1028 idx.insert(2, "131")?;
1058 idx.insert(3, "cafe")?;
1029 idx.insert(3, "cafe")?;
1059 let mut idx = idx.commit();
1030 let mut idx = idx.commit();
1060
1031
1061 idx.nt.invalidate_all();
1032 idx.nt.invalidate_all();
1062
1033
1063 assert_eq!(idx.find_hex("1234")?, None);
1034 assert_eq!(idx.find_hex("1234")?, None);
1064 assert_eq!(idx.find_hex("1235")?, None);
1035 assert_eq!(idx.find_hex("1235")?, None);
1065 assert_eq!(idx.find_hex("131")?, None);
1036 assert_eq!(idx.find_hex("131")?, None);
1066 assert_eq!(idx.find_hex("cafe")?, None);
1037 assert_eq!(idx.find_hex("cafe")?, None);
1067 // all the readonly blocks have been masked, this is the
1038 // all the readonly blocks have been masked, this is the
1068 // conventional expected response
1039 // conventional expected response
1069 assert_eq!(idx.nt.masked_readonly_blocks(), idx.nt.readonly.len() + 1);
1040 assert_eq!(idx.nt.masked_readonly_blocks(), idx.nt.readonly.len() + 1);
1070 Ok(())
1041 Ok(())
1071 }
1042 }
1072
1043
1073 #[test]
1044 #[test]
1074 fn test_into_added_empty() {
1045 fn test_into_added_empty() {
1075 assert!(sample_nodetree().into_readonly_and_added().1.is_empty());
1046 assert!(sample_nodetree().into_readonly_and_added().1.is_empty());
1076 assert!(sample_nodetree()
1047 assert!(sample_nodetree()
1077 .into_readonly_and_added_bytes()
1048 .into_readonly_and_added_bytes()
1078 .1
1049 .1
1079 .is_empty());
1050 .is_empty());
1080 }
1051 }
1081
1052
1082 #[test]
1053 #[test]
1083 fn test_into_added_bytes() -> Result<(), NodeMapError> {
1054 fn test_into_added_bytes() -> Result<(), NodeMapError> {
1084 let mut idx = TestNtIndex::new();
1055 let mut idx = TestNtIndex::new();
1085 idx.insert(0, "1234")?;
1056 idx.insert(0, "1234")?;
1086 let mut idx = idx.commit();
1057 let mut idx = idx.commit();
1087 idx.insert(4, "cafe")?;
1058 idx.insert(4, "cafe")?;
1088 let (_, bytes) = idx.nt.into_readonly_and_added_bytes();
1059 let (_, bytes) = idx.nt.into_readonly_and_added_bytes();
1089
1060
1090 // only the root block has been changed
1061 // only the root block has been changed
1091 assert_eq!(bytes.len(), size_of::<Block>());
1062 assert_eq!(bytes.len(), size_of::<Block>());
1092 // big endian for -2
1063 // big endian for -2
1093 assert_eq!(&bytes[4..2 * 4], [255, 255, 255, 254]);
1064 assert_eq!(&bytes[4..2 * 4], [255, 255, 255, 254]);
1094 // big endian for -6
1065 // big endian for -6
1095 assert_eq!(&bytes[12 * 4..13 * 4], [255, 255, 255, 250]);
1066 assert_eq!(&bytes[12 * 4..13 * 4], [255, 255, 255, 250]);
1096 Ok(())
1067 Ok(())
1097 }
1068 }
1098 }
1069 }
@@ -1,491 +1,490
1 // revlog.rs
1 // revlog.rs
2 //
2 //
3 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
3 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::{
8 use crate::{
9 cindex,
9 cindex,
10 utils::{node_from_py_bytes, node_from_py_object},
10 utils::{node_from_py_bytes, node_from_py_object},
11 };
11 };
12 use cpython::{
12 use cpython::{
13 buffer::{Element, PyBuffer},
13 buffer::{Element, PyBuffer},
14 exc::{IndexError, ValueError},
14 exc::{IndexError, ValueError},
15 ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
15 ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
16 PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
16 PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
17 };
17 };
18 use hg::{
18 use hg::{
19 nodemap::{Block, NodeMapError, NodeTree},
19 nodemap::{Block, NodeMapError, NodeTree},
20 revlog::{nodemap::NodeMap, RevlogIndex},
20 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
21 Revision,
21 Revision,
22 };
22 };
23 use std::cell::RefCell;
23 use std::cell::RefCell;
24
24
25 /// Return a Struct implementing the Graph trait
25 /// Return a Struct implementing the Graph trait
26 pub(crate) fn pyindex_to_graph(
26 pub(crate) fn pyindex_to_graph(
27 py: Python,
27 py: Python,
28 index: PyObject,
28 index: PyObject,
29 ) -> PyResult<cindex::Index> {
29 ) -> PyResult<cindex::Index> {
30 match index.extract::<MixedIndex>(py) {
30 match index.extract::<MixedIndex>(py) {
31 Ok(midx) => Ok(midx.clone_cindex(py)),
31 Ok(midx) => Ok(midx.clone_cindex(py)),
32 Err(_) => cindex::Index::new(py, index),
32 Err(_) => cindex::Index::new(py, index),
33 }
33 }
34 }
34 }
35
35
36 py_class!(pub class MixedIndex |py| {
36 py_class!(pub class MixedIndex |py| {
37 data cindex: RefCell<cindex::Index>;
37 data cindex: RefCell<cindex::Index>;
38 data nt: RefCell<Option<NodeTree>>;
38 data nt: RefCell<Option<NodeTree>>;
39 data docket: RefCell<Option<PyObject>>;
39 data docket: RefCell<Option<PyObject>>;
40 // Holds a reference to the mmap'ed persistent nodemap data
40 // Holds a reference to the mmap'ed persistent nodemap data
41 data mmap: RefCell<Option<PyBuffer>>;
41 data mmap: RefCell<Option<PyBuffer>>;
42
42
43 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
43 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
44 Self::new(py, cindex)
44 Self::new(py, cindex)
45 }
45 }
46
46
47 /// Compatibility layer used for Python consumers needing access to the C index
47 /// Compatibility layer used for Python consumers needing access to the C index
48 ///
48 ///
49 /// Only use case so far is `scmutil.shortesthexnodeidprefix`,
49 /// Only use case so far is `scmutil.shortesthexnodeidprefix`,
50 /// that may need to build a custom `nodetree`, based on a specified revset.
50 /// that may need to build a custom `nodetree`, based on a specified revset.
51 /// With a Rust implementation of the nodemap, we will be able to get rid of
51 /// With a Rust implementation of the nodemap, we will be able to get rid of
52 /// this, by exposing our own standalone nodemap class,
52 /// this, by exposing our own standalone nodemap class,
53 /// ready to accept `MixedIndex`.
53 /// ready to accept `MixedIndex`.
54 def get_cindex(&self) -> PyResult<PyObject> {
54 def get_cindex(&self) -> PyResult<PyObject> {
55 Ok(self.cindex(py).borrow().inner().clone_ref(py))
55 Ok(self.cindex(py).borrow().inner().clone_ref(py))
56 }
56 }
57
57
58 // Index API involving nodemap, as defined in mercurial/pure/parsers.py
58 // Index API involving nodemap, as defined in mercurial/pure/parsers.py
59
59
60 /// Return Revision if found, raises a bare `error.RevlogError`
60 /// Return Revision if found, raises a bare `error.RevlogError`
61 /// in case of ambiguity, same as C version does
61 /// in case of ambiguity, same as C version does
62 def get_rev(&self, node: PyBytes) -> PyResult<Option<Revision>> {
62 def get_rev(&self, node: PyBytes) -> PyResult<Option<Revision>> {
63 let opt = self.get_nodetree(py)?.borrow();
63 let opt = self.get_nodetree(py)?.borrow();
64 let nt = opt.as_ref().unwrap();
64 let nt = opt.as_ref().unwrap();
65 let idx = &*self.cindex(py).borrow();
65 let idx = &*self.cindex(py).borrow();
66 let node = node_from_py_bytes(py, &node)?;
66 let node = node_from_py_bytes(py, &node)?;
67 nt.find_bin(idx, node.into()).map_err(|e| nodemap_error(py, e))
67 nt.find_bin(idx, node.into()).map_err(|e| nodemap_error(py, e))
68 }
68 }
69
69
70 /// same as `get_rev()` but raises a bare `error.RevlogError` if node
70 /// same as `get_rev()` but raises a bare `error.RevlogError` if node
71 /// is not found.
71 /// is not found.
72 ///
72 ///
73 /// No need to repeat `node` in the exception, `mercurial/revlog.py`
73 /// No need to repeat `node` in the exception, `mercurial/revlog.py`
74 /// will catch and rewrap with it
74 /// will catch and rewrap with it
75 def rev(&self, node: PyBytes) -> PyResult<Revision> {
75 def rev(&self, node: PyBytes) -> PyResult<Revision> {
76 self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
76 self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
77 }
77 }
78
78
79 /// return True if the node exist in the index
79 /// return True if the node exist in the index
80 def has_node(&self, node: PyBytes) -> PyResult<bool> {
80 def has_node(&self, node: PyBytes) -> PyResult<bool> {
81 self.get_rev(py, node).map(|opt| opt.is_some())
81 self.get_rev(py, node).map(|opt| opt.is_some())
82 }
82 }
83
83
84 /// find length of shortest hex nodeid of a binary ID
84 /// find length of shortest hex nodeid of a binary ID
85 def shortest(&self, node: PyBytes) -> PyResult<usize> {
85 def shortest(&self, node: PyBytes) -> PyResult<usize> {
86 let opt = self.get_nodetree(py)?.borrow();
86 let opt = self.get_nodetree(py)?.borrow();
87 let nt = opt.as_ref().unwrap();
87 let nt = opt.as_ref().unwrap();
88 let idx = &*self.cindex(py).borrow();
88 let idx = &*self.cindex(py).borrow();
89 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?)
89 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?)
90 {
90 {
91 Ok(Some(l)) => Ok(l),
91 Ok(Some(l)) => Ok(l),
92 Ok(None) => Err(revlog_error(py)),
92 Ok(None) => Err(revlog_error(py)),
93 Err(e) => Err(nodemap_error(py, e)),
93 Err(e) => Err(nodemap_error(py, e)),
94 }
94 }
95 }
95 }
96
96
97 def partialmatch(&self, node: PyObject) -> PyResult<Option<PyBytes>> {
97 def partialmatch(&self, node: PyObject) -> PyResult<Option<PyBytes>> {
98 let opt = self.get_nodetree(py)?.borrow();
98 let opt = self.get_nodetree(py)?.borrow();
99 let nt = opt.as_ref().unwrap();
99 let nt = opt.as_ref().unwrap();
100 let idx = &*self.cindex(py).borrow();
100 let idx = &*self.cindex(py).borrow();
101
101
102 let node_as_string = if cfg!(feature = "python3-sys") {
102 let node_as_string = if cfg!(feature = "python3-sys") {
103 node.cast_as::<PyString>(py)?.to_string(py)?.to_string()
103 node.cast_as::<PyString>(py)?.to_string(py)?.to_string()
104 }
104 }
105 else {
105 else {
106 let node = node.extract::<PyBytes>(py)?;
106 let node = node.extract::<PyBytes>(py)?;
107 String::from_utf8_lossy(node.data(py)).to_string()
107 String::from_utf8_lossy(node.data(py)).to_string()
108 };
108 };
109
109
110 nt.find_hex(idx, &node_as_string)
110 let prefix = NodePrefix::from_hex(&node_as_string).map_err(|_| PyErr::new::<ValueError, _>(py, "Invalid node or prefix"))?;
111
112 nt.find_bin(idx, prefix)
111 // TODO make an inner API returning the node directly
113 // TODO make an inner API returning the node directly
112 .map(|opt| opt.map(
114 .map(|opt| opt.map(
113 |rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes())))
115 |rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes())))
114 .map_err(|e| nodemap_error(py, e))
116 .map_err(|e| nodemap_error(py, e))
115
117
116 }
118 }
117
119
118 /// append an index entry
120 /// append an index entry
119 def append(&self, tup: PyTuple) -> PyResult<PyObject> {
121 def append(&self, tup: PyTuple) -> PyResult<PyObject> {
120 if tup.len(py) < 8 {
122 if tup.len(py) < 8 {
121 // this is better than the panic promised by tup.get_item()
123 // this is better than the panic promised by tup.get_item()
122 return Err(
124 return Err(
123 PyErr::new::<IndexError, _>(py, "tuple index out of range"))
125 PyErr::new::<IndexError, _>(py, "tuple index out of range"))
124 }
126 }
125 let node_bytes = tup.get_item(py, 7).extract(py)?;
127 let node_bytes = tup.get_item(py, 7).extract(py)?;
126 let node = node_from_py_object(py, &node_bytes)?;
128 let node = node_from_py_object(py, &node_bytes)?;
127
129
128 let mut idx = self.cindex(py).borrow_mut();
130 let mut idx = self.cindex(py).borrow_mut();
129 let rev = idx.len() as Revision;
131 let rev = idx.len() as Revision;
130
132
131 idx.append(py, tup)?;
133 idx.append(py, tup)?;
132 self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
134 self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
133 .insert(&*idx, &node, rev)
135 .insert(&*idx, &node, rev)
134 .map_err(|e| nodemap_error(py, e))?;
136 .map_err(|e| nodemap_error(py, e))?;
135 Ok(py.None())
137 Ok(py.None())
136 }
138 }
137
139
138 def __delitem__(&self, key: PyObject) -> PyResult<()> {
140 def __delitem__(&self, key: PyObject) -> PyResult<()> {
139 // __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
141 // __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
140 self.cindex(py).borrow().inner().del_item(py, key)?;
142 self.cindex(py).borrow().inner().del_item(py, key)?;
141 let mut opt = self.get_nodetree(py)?.borrow_mut();
143 let mut opt = self.get_nodetree(py)?.borrow_mut();
142 let mut nt = opt.as_mut().unwrap();
144 let mut nt = opt.as_mut().unwrap();
143 nt.invalidate_all();
145 nt.invalidate_all();
144 self.fill_nodemap(py, &mut nt)?;
146 self.fill_nodemap(py, &mut nt)?;
145 Ok(())
147 Ok(())
146 }
148 }
147
149
148 //
150 //
149 // Reforwarded C index API
151 // Reforwarded C index API
150 //
152 //
151
153
152 // index_methods (tp_methods). Same ordering as in revlog.c
154 // index_methods (tp_methods). Same ordering as in revlog.c
153
155
154 /// return the gca set of the given revs
156 /// return the gca set of the given revs
155 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
157 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
156 self.call_cindex(py, "ancestors", args, kw)
158 self.call_cindex(py, "ancestors", args, kw)
157 }
159 }
158
160
159 /// return the heads of the common ancestors of the given revs
161 /// return the heads of the common ancestors of the given revs
160 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
162 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
161 self.call_cindex(py, "commonancestorsheads", args, kw)
163 self.call_cindex(py, "commonancestorsheads", args, kw)
162 }
164 }
163
165
164 /// Clear the index caches and inner py_class data.
166 /// Clear the index caches and inner py_class data.
165 /// It is Python's responsibility to call `update_nodemap_data` again.
167 /// It is Python's responsibility to call `update_nodemap_data` again.
166 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
168 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
167 self.nt(py).borrow_mut().take();
169 self.nt(py).borrow_mut().take();
168 self.docket(py).borrow_mut().take();
170 self.docket(py).borrow_mut().take();
169 self.mmap(py).borrow_mut().take();
171 self.mmap(py).borrow_mut().take();
170 self.call_cindex(py, "clearcaches", args, kw)
172 self.call_cindex(py, "clearcaches", args, kw)
171 }
173 }
172
174
173 /// get an index entry
175 /// get an index entry
174 def get(&self, *args, **kw) -> PyResult<PyObject> {
176 def get(&self, *args, **kw) -> PyResult<PyObject> {
175 self.call_cindex(py, "get", args, kw)
177 self.call_cindex(py, "get", args, kw)
176 }
178 }
177
179
178 /// compute phases
180 /// compute phases
179 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
181 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
180 self.call_cindex(py, "computephasesmapsets", args, kw)
182 self.call_cindex(py, "computephasesmapsets", args, kw)
181 }
183 }
182
184
183 /// reachableroots
185 /// reachableroots
184 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
186 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
185 self.call_cindex(py, "reachableroots2", args, kw)
187 self.call_cindex(py, "reachableroots2", args, kw)
186 }
188 }
187
189
188 /// get head revisions
190 /// get head revisions
189 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
191 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
190 self.call_cindex(py, "headrevs", args, kw)
192 self.call_cindex(py, "headrevs", args, kw)
191 }
193 }
192
194
193 /// get filtered head revisions
195 /// get filtered head revisions
194 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
196 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
195 self.call_cindex(py, "headrevsfiltered", args, kw)
197 self.call_cindex(py, "headrevsfiltered", args, kw)
196 }
198 }
197
199
198 /// True if the object is a snapshot
200 /// True if the object is a snapshot
199 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
201 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
200 self.call_cindex(py, "issnapshot", args, kw)
202 self.call_cindex(py, "issnapshot", args, kw)
201 }
203 }
202
204
203 /// Gather snapshot data in a cache dict
205 /// Gather snapshot data in a cache dict
204 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
206 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
205 self.call_cindex(py, "findsnapshots", args, kw)
207 self.call_cindex(py, "findsnapshots", args, kw)
206 }
208 }
207
209
208 /// determine revisions with deltas to reconstruct fulltext
210 /// determine revisions with deltas to reconstruct fulltext
209 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
211 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
210 self.call_cindex(py, "deltachain", args, kw)
212 self.call_cindex(py, "deltachain", args, kw)
211 }
213 }
212
214
213 /// slice planned chunk read to reach a density threshold
215 /// slice planned chunk read to reach a density threshold
214 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
216 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
215 self.call_cindex(py, "slicechunktodensity", args, kw)
217 self.call_cindex(py, "slicechunktodensity", args, kw)
216 }
218 }
217
219
218 /// stats for the index
220 /// stats for the index
219 def stats(&self, *args, **kw) -> PyResult<PyObject> {
221 def stats(&self, *args, **kw) -> PyResult<PyObject> {
220 self.call_cindex(py, "stats", args, kw)
222 self.call_cindex(py, "stats", args, kw)
221 }
223 }
222
224
223 // index_sequence_methods and index_mapping_methods.
225 // index_sequence_methods and index_mapping_methods.
224 //
226 //
225 // Since we call back through the high level Python API,
227 // Since we call back through the high level Python API,
226 // there's no point making a distinction between index_get
228 // there's no point making a distinction between index_get
227 // and index_getitem.
229 // and index_getitem.
228
230
229 def __len__(&self) -> PyResult<usize> {
231 def __len__(&self) -> PyResult<usize> {
230 self.cindex(py).borrow().inner().len(py)
232 self.cindex(py).borrow().inner().len(py)
231 }
233 }
232
234
233 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
235 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
234 // this conversion seems needless, but that's actually because
236 // this conversion seems needless, but that's actually because
235 // `index_getitem` does not handle conversion from PyLong,
237 // `index_getitem` does not handle conversion from PyLong,
236 // which expressions such as [e for e in index] internally use.
238 // which expressions such as [e for e in index] internally use.
237 // Note that we don't seem to have a direct way to call
239 // Note that we don't seem to have a direct way to call
238 // PySequence_GetItem (does the job), which would possibly be better
240 // PySequence_GetItem (does the job), which would possibly be better
239 // for performance
241 // for performance
240 let key = match key.extract::<Revision>(py) {
242 let key = match key.extract::<Revision>(py) {
241 Ok(rev) => rev.to_py_object(py).into_object(),
243 Ok(rev) => rev.to_py_object(py).into_object(),
242 Err(_) => key,
244 Err(_) => key,
243 };
245 };
244 self.cindex(py).borrow().inner().get_item(py, key)
246 self.cindex(py).borrow().inner().get_item(py, key)
245 }
247 }
246
248
247 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
249 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
248 self.cindex(py).borrow().inner().set_item(py, key, value)
250 self.cindex(py).borrow().inner().set_item(py, key, value)
249 }
251 }
250
252
251 def __contains__(&self, item: PyObject) -> PyResult<bool> {
253 def __contains__(&self, item: PyObject) -> PyResult<bool> {
252 // ObjectProtocol does not seem to provide contains(), so
254 // ObjectProtocol does not seem to provide contains(), so
253 // this is an equivalent implementation of the index_contains()
255 // this is an equivalent implementation of the index_contains()
254 // defined in revlog.c
256 // defined in revlog.c
255 let cindex = self.cindex(py).borrow();
257 let cindex = self.cindex(py).borrow();
256 match item.extract::<Revision>(py) {
258 match item.extract::<Revision>(py) {
257 Ok(rev) => {
259 Ok(rev) => {
258 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
260 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
259 }
261 }
260 Err(_) => {
262 Err(_) => {
261 cindex.inner().call_method(
263 cindex.inner().call_method(
262 py,
264 py,
263 "has_node",
265 "has_node",
264 PyTuple::new(py, &[item]),
266 PyTuple::new(py, &[item]),
265 None)?
267 None)?
266 .extract(py)
268 .extract(py)
267 }
269 }
268 }
270 }
269 }
271 }
270
272
271 def nodemap_data_all(&self) -> PyResult<PyBytes> {
273 def nodemap_data_all(&self) -> PyResult<PyBytes> {
272 self.inner_nodemap_data_all(py)
274 self.inner_nodemap_data_all(py)
273 }
275 }
274
276
275 def nodemap_data_incremental(&self) -> PyResult<PyObject> {
277 def nodemap_data_incremental(&self) -> PyResult<PyObject> {
276 self.inner_nodemap_data_incremental(py)
278 self.inner_nodemap_data_incremental(py)
277 }
279 }
278 def update_nodemap_data(
280 def update_nodemap_data(
279 &self,
281 &self,
280 docket: PyObject,
282 docket: PyObject,
281 nm_data: PyObject
283 nm_data: PyObject
282 ) -> PyResult<PyObject> {
284 ) -> PyResult<PyObject> {
283 self.inner_update_nodemap_data(py, docket, nm_data)
285 self.inner_update_nodemap_data(py, docket, nm_data)
284 }
286 }
285
287
286
288
287 });
289 });
288
290
289 impl MixedIndex {
291 impl MixedIndex {
290 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> {
292 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> {
291 Self::create_instance(
293 Self::create_instance(
292 py,
294 py,
293 RefCell::new(cindex::Index::new(py, cindex)?),
295 RefCell::new(cindex::Index::new(py, cindex)?),
294 RefCell::new(None),
296 RefCell::new(None),
295 RefCell::new(None),
297 RefCell::new(None),
296 RefCell::new(None),
298 RefCell::new(None),
297 )
299 )
298 }
300 }
299
301
300 /// This is scaffolding at this point, but it could also become
302 /// This is scaffolding at this point, but it could also become
301 /// a way to start a persistent nodemap or perform a
303 /// a way to start a persistent nodemap or perform a
302 /// vacuum / repack operation
304 /// vacuum / repack operation
303 fn fill_nodemap(
305 fn fill_nodemap(
304 &self,
306 &self,
305 py: Python,
307 py: Python,
306 nt: &mut NodeTree,
308 nt: &mut NodeTree,
307 ) -> PyResult<PyObject> {
309 ) -> PyResult<PyObject> {
308 let index = self.cindex(py).borrow();
310 let index = self.cindex(py).borrow();
309 for r in 0..index.len() {
311 for r in 0..index.len() {
310 let rev = r as Revision;
312 let rev = r as Revision;
311 // in this case node() won't ever return None
313 // in this case node() won't ever return None
312 nt.insert(&*index, index.node(rev).unwrap(), rev)
314 nt.insert(&*index, index.node(rev).unwrap(), rev)
313 .map_err(|e| nodemap_error(py, e))?
315 .map_err(|e| nodemap_error(py, e))?
314 }
316 }
315 Ok(py.None())
317 Ok(py.None())
316 }
318 }
317
319
318 fn get_nodetree<'a>(
320 fn get_nodetree<'a>(
319 &'a self,
321 &'a self,
320 py: Python<'a>,
322 py: Python<'a>,
321 ) -> PyResult<&'a RefCell<Option<NodeTree>>> {
323 ) -> PyResult<&'a RefCell<Option<NodeTree>>> {
322 if self.nt(py).borrow().is_none() {
324 if self.nt(py).borrow().is_none() {
323 let readonly = Box::new(Vec::new());
325 let readonly = Box::new(Vec::new());
324 let mut nt = NodeTree::load_bytes(readonly, 0);
326 let mut nt = NodeTree::load_bytes(readonly, 0);
325 self.fill_nodemap(py, &mut nt)?;
327 self.fill_nodemap(py, &mut nt)?;
326 self.nt(py).borrow_mut().replace(nt);
328 self.nt(py).borrow_mut().replace(nt);
327 }
329 }
328 Ok(self.nt(py))
330 Ok(self.nt(py))
329 }
331 }
330
332
331 /// forward a method call to the underlying C index
333 /// forward a method call to the underlying C index
332 fn call_cindex(
334 fn call_cindex(
333 &self,
335 &self,
334 py: Python,
336 py: Python,
335 name: &str,
337 name: &str,
336 args: &PyTuple,
338 args: &PyTuple,
337 kwargs: Option<&PyDict>,
339 kwargs: Option<&PyDict>,
338 ) -> PyResult<PyObject> {
340 ) -> PyResult<PyObject> {
339 self.cindex(py)
341 self.cindex(py)
340 .borrow()
342 .borrow()
341 .inner()
343 .inner()
342 .call_method(py, name, args, kwargs)
344 .call_method(py, name, args, kwargs)
343 }
345 }
344
346
345 pub fn clone_cindex(&self, py: Python) -> cindex::Index {
347 pub fn clone_cindex(&self, py: Python) -> cindex::Index {
346 self.cindex(py).borrow().clone_ref(py)
348 self.cindex(py).borrow().clone_ref(py)
347 }
349 }
348
350
349 /// Returns the full nodemap bytes to be written as-is to disk
351 /// Returns the full nodemap bytes to be written as-is to disk
350 fn inner_nodemap_data_all(&self, py: Python) -> PyResult<PyBytes> {
352 fn inner_nodemap_data_all(&self, py: Python) -> PyResult<PyBytes> {
351 let nodemap = self.get_nodetree(py)?.borrow_mut().take().unwrap();
353 let nodemap = self.get_nodetree(py)?.borrow_mut().take().unwrap();
352 let (readonly, bytes) = nodemap.into_readonly_and_added_bytes();
354 let (readonly, bytes) = nodemap.into_readonly_and_added_bytes();
353
355
354 // If there's anything readonly, we need to build the data again from
356 // If there's anything readonly, we need to build the data again from
355 // scratch
357 // scratch
356 let bytes = if readonly.len() > 0 {
358 let bytes = if readonly.len() > 0 {
357 let mut nt = NodeTree::load_bytes(Box::new(vec![]), 0);
359 let mut nt = NodeTree::load_bytes(Box::new(vec![]), 0);
358 self.fill_nodemap(py, &mut nt)?;
360 self.fill_nodemap(py, &mut nt)?;
359
361
360 let (readonly, bytes) = nt.into_readonly_and_added_bytes();
362 let (readonly, bytes) = nt.into_readonly_and_added_bytes();
361 assert_eq!(readonly.len(), 0);
363 assert_eq!(readonly.len(), 0);
362
364
363 bytes
365 bytes
364 } else {
366 } else {
365 bytes
367 bytes
366 };
368 };
367
369
368 let bytes = PyBytes::new(py, &bytes);
370 let bytes = PyBytes::new(py, &bytes);
369 Ok(bytes)
371 Ok(bytes)
370 }
372 }
371
373
372 /// Returns the last saved docket along with the size of any changed data
374 /// Returns the last saved docket along with the size of any changed data
373 /// (in number of blocks), and said data as bytes.
375 /// (in number of blocks), and said data as bytes.
374 fn inner_nodemap_data_incremental(
376 fn inner_nodemap_data_incremental(
375 &self,
377 &self,
376 py: Python,
378 py: Python,
377 ) -> PyResult<PyObject> {
379 ) -> PyResult<PyObject> {
378 let docket = self.docket(py).borrow();
380 let docket = self.docket(py).borrow();
379 let docket = match docket.as_ref() {
381 let docket = match docket.as_ref() {
380 Some(d) => d,
382 Some(d) => d,
381 None => return Ok(py.None()),
383 None => return Ok(py.None()),
382 };
384 };
383
385
384 let node_tree = self.get_nodetree(py)?.borrow_mut().take().unwrap();
386 let node_tree = self.get_nodetree(py)?.borrow_mut().take().unwrap();
385 let masked_blocks = node_tree.masked_readonly_blocks();
387 let masked_blocks = node_tree.masked_readonly_blocks();
386 let (_, data) = node_tree.into_readonly_and_added_bytes();
388 let (_, data) = node_tree.into_readonly_and_added_bytes();
387 let changed = masked_blocks * std::mem::size_of::<Block>();
389 let changed = masked_blocks * std::mem::size_of::<Block>();
388
390
389 Ok((docket, changed, PyBytes::new(py, &data))
391 Ok((docket, changed, PyBytes::new(py, &data))
390 .to_py_object(py)
392 .to_py_object(py)
391 .into_object())
393 .into_object())
392 }
394 }
393
395
394 /// Update the nodemap from the new (mmaped) data.
396 /// Update the nodemap from the new (mmaped) data.
395 /// The docket is kept as a reference for later incremental calls.
397 /// The docket is kept as a reference for later incremental calls.
396 fn inner_update_nodemap_data(
398 fn inner_update_nodemap_data(
397 &self,
399 &self,
398 py: Python,
400 py: Python,
399 docket: PyObject,
401 docket: PyObject,
400 nm_data: PyObject,
402 nm_data: PyObject,
401 ) -> PyResult<PyObject> {
403 ) -> PyResult<PyObject> {
402 let buf = PyBuffer::get(py, &nm_data)?;
404 let buf = PyBuffer::get(py, &nm_data)?;
403 let len = buf.item_count();
405 let len = buf.item_count();
404
406
405 // Build a slice from the mmap'ed buffer data
407 // Build a slice from the mmap'ed buffer data
406 let cbuf = buf.buf_ptr();
408 let cbuf = buf.buf_ptr();
407 let bytes = if std::mem::size_of::<u8>() == buf.item_size()
409 let bytes = if std::mem::size_of::<u8>() == buf.item_size()
408 && buf.is_c_contiguous()
410 && buf.is_c_contiguous()
409 && u8::is_compatible_format(buf.format())
411 && u8::is_compatible_format(buf.format())
410 {
412 {
411 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
413 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
412 } else {
414 } else {
413 return Err(PyErr::new::<ValueError, _>(
415 return Err(PyErr::new::<ValueError, _>(
414 py,
416 py,
415 "Nodemap data buffer has an invalid memory representation"
417 "Nodemap data buffer has an invalid memory representation"
416 .to_string(),
418 .to_string(),
417 ));
419 ));
418 };
420 };
419
421
420 // Keep a reference to the mmap'ed buffer, otherwise we get a dangling
422 // Keep a reference to the mmap'ed buffer, otherwise we get a dangling
421 // pointer.
423 // pointer.
422 self.mmap(py).borrow_mut().replace(buf);
424 self.mmap(py).borrow_mut().replace(buf);
423
425
424 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
426 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
425
427
426 let data_tip =
428 let data_tip =
427 docket.getattr(py, "tip_rev")?.extract::<Revision>(py)?;
429 docket.getattr(py, "tip_rev")?.extract::<Revision>(py)?;
428 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
430 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
429 let idx = self.cindex(py).borrow();
431 let idx = self.cindex(py).borrow();
430 let current_tip = idx.len();
432 let current_tip = idx.len();
431
433
432 for r in (data_tip + 1)..current_tip as Revision {
434 for r in (data_tip + 1)..current_tip as Revision {
433 let rev = r as Revision;
435 let rev = r as Revision;
434 // in this case node() won't ever return None
436 // in this case node() won't ever return None
435 nt.insert(&*idx, idx.node(rev).unwrap(), rev)
437 nt.insert(&*idx, idx.node(rev).unwrap(), rev)
436 .map_err(|e| nodemap_error(py, e))?
438 .map_err(|e| nodemap_error(py, e))?
437 }
439 }
438
440
439 *self.nt(py).borrow_mut() = Some(nt);
441 *self.nt(py).borrow_mut() = Some(nt);
440
442
441 Ok(py.None())
443 Ok(py.None())
442 }
444 }
443 }
445 }
444
446
445 fn revlog_error(py: Python) -> PyErr {
447 fn revlog_error(py: Python) -> PyErr {
446 match py
448 match py
447 .import("mercurial.error")
449 .import("mercurial.error")
448 .and_then(|m| m.get(py, "RevlogError"))
450 .and_then(|m| m.get(py, "RevlogError"))
449 {
451 {
450 Err(e) => e,
452 Err(e) => e,
451 Ok(cls) => PyErr::from_instance(py, cls),
453 Ok(cls) => PyErr::from_instance(py, cls),
452 }
454 }
453 }
455 }
454
456
455 fn rev_not_in_index(py: Python, rev: Revision) -> PyErr {
457 fn rev_not_in_index(py: Python, rev: Revision) -> PyErr {
456 PyErr::new::<ValueError, _>(
458 PyErr::new::<ValueError, _>(
457 py,
459 py,
458 format!(
460 format!(
459 "Inconsistency: Revision {} found in nodemap \
461 "Inconsistency: Revision {} found in nodemap \
460 is not in revlog index",
462 is not in revlog index",
461 rev
463 rev
462 ),
464 ),
463 )
465 )
464 }
466 }
465
467
466 /// Standard treatment of NodeMapError
468 /// Standard treatment of NodeMapError
467 fn nodemap_error(py: Python, err: NodeMapError) -> PyErr {
469 fn nodemap_error(py: Python, err: NodeMapError) -> PyErr {
468 match err {
470 match err {
469 NodeMapError::MultipleResults => revlog_error(py),
471 NodeMapError::MultipleResults => revlog_error(py),
470 NodeMapError::RevisionNotInIndex(r) => rev_not_in_index(py, r),
472 NodeMapError::RevisionNotInIndex(r) => rev_not_in_index(py, r),
471 NodeMapError::InvalidNodePrefix => {
472 PyErr::new::<ValueError, _>(py, "Invalid node or prefix")
473 }
474 }
473 }
475 }
474 }
476
475
477 /// Create the module, with __package__ given from parent
476 /// Create the module, with __package__ given from parent
478 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
477 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
479 let dotted_name = &format!("{}.revlog", package);
478 let dotted_name = &format!("{}.revlog", package);
480 let m = PyModule::new(py, dotted_name)?;
479 let m = PyModule::new(py, dotted_name)?;
481 m.add(py, "__package__", package)?;
480 m.add(py, "__package__", package)?;
482 m.add(py, "__doc__", "RevLog - Rust implementations")?;
481 m.add(py, "__doc__", "RevLog - Rust implementations")?;
483
482
484 m.add_class::<MixedIndex>(py)?;
483 m.add_class::<MixedIndex>(py)?;
485
484
486 let sys = PyModule::import(py, "sys")?;
485 let sys = PyModule::import(py, "sys")?;
487 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
486 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
488 sys_modules.set_item(py, dotted_name, &m)?;
487 sys_modules.set_item(py, dotted_name, &m)?;
489
488
490 Ok(m)
489 Ok(m)
491 }
490 }
General Comments 0
You need to be logged in to leave comments. Login now