##// END OF EJS Templates
rust-nodemap: insert method...
Georges Racinet -
r44831:d2da8667 default
parent child Browse files
Show More
@@ -1,526 +1,790 b''
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, NodeError, NodePrefix, NodePrefixRef, Revision, RevlogIndex,
16 Node, NodeError, NodePrefix, NodePrefixRef, Revision, RevlogIndex,
17 };
17 };
18
18 use std::fmt;
19 use std::fmt;
19 use std::ops::Deref;
20 use std::ops::Deref;
20 use std::ops::Index;
21 use std::ops::Index;
21
22
22 #[derive(Debug, PartialEq)]
23 #[derive(Debug, PartialEq)]
23 pub enum NodeMapError {
24 pub enum NodeMapError {
24 MultipleResults,
25 MultipleResults,
25 InvalidNodePrefix(NodeError),
26 InvalidNodePrefix(NodeError),
26 /// A `Revision` stored in the nodemap could not be found in the index
27 /// A `Revision` stored in the nodemap could not be found in the index
27 RevisionNotInIndex(Revision),
28 RevisionNotInIndex(Revision),
28 }
29 }
29
30
30 impl From<NodeError> for NodeMapError {
31 impl From<NodeError> for NodeMapError {
31 fn from(err: NodeError) -> Self {
32 fn from(err: NodeError) -> Self {
32 NodeMapError::InvalidNodePrefix(err)
33 NodeMapError::InvalidNodePrefix(err)
33 }
34 }
34 }
35 }
35
36
36 /// Mapping system from Mercurial nodes to revision numbers.
37 /// Mapping system from Mercurial nodes to revision numbers.
37 ///
38 ///
38 /// ## `RevlogIndex` and `NodeMap`
39 /// ## `RevlogIndex` and `NodeMap`
39 ///
40 ///
40 /// One way to think about their relationship is that
41 /// One way to think about their relationship is that
41 /// the `NodeMap` is a prefix-oriented reverse index of the `Node` information
42 /// the `NodeMap` is a prefix-oriented reverse index of the `Node` information
42 /// carried by a [`RevlogIndex`].
43 /// carried by a [`RevlogIndex`].
43 ///
44 ///
44 /// Many of the methods in this trait take a `RevlogIndex` argument
45 /// Many of the methods in this trait take a `RevlogIndex` argument
45 /// which is used for validation of their results. This index must naturally
46 /// which is used for validation of their results. This index must naturally
46 /// be the one the `NodeMap` is about, and it must be consistent.
47 /// be the one the `NodeMap` is about, and it must be consistent.
47 ///
48 ///
48 /// Notably, the `NodeMap` must not store
49 /// Notably, the `NodeMap` must not store
49 /// information about more `Revision` values than there are in the index.
50 /// information about more `Revision` values than there are in the index.
50 /// In these methods, an encountered `Revision` is not in the index, a
51 /// In these methods, an encountered `Revision` is not in the index, a
51 /// [`RevisionNotInIndex`] error is returned.
52 /// [`RevisionNotInIndex`] error is returned.
52 ///
53 ///
53 /// In insert operations, the rule is thus that the `NodeMap` must always
54 /// In insert operations, the rule is thus that the `NodeMap` must always
54 /// be updated after the `RevlogIndex`
55 /// be updated after the `RevlogIndex`
55 /// be updated first, and the `NodeMap` second.
56 /// be updated first, and the `NodeMap` second.
56 ///
57 ///
57 /// [`RevisionNotInIndex`]: enum.NodeMapError.html#variant.RevisionNotInIndex
58 /// [`RevisionNotInIndex`]: enum.NodeMapError.html#variant.RevisionNotInIndex
58 /// [`RevlogIndex`]: ../trait.RevlogIndex.html
59 /// [`RevlogIndex`]: ../trait.RevlogIndex.html
59 pub trait NodeMap {
60 pub trait NodeMap {
60 /// Find the unique `Revision` having the given `Node`
61 /// Find the unique `Revision` having the given `Node`
61 ///
62 ///
62 /// If no Revision matches the given `Node`, `Ok(None)` is returned.
63 /// If no Revision matches the given `Node`, `Ok(None)` is returned.
63 fn find_node(
64 fn find_node(
64 &self,
65 &self,
65 index: &impl RevlogIndex,
66 index: &impl RevlogIndex,
66 node: &Node,
67 node: &Node,
67 ) -> Result<Option<Revision>, NodeMapError> {
68 ) -> Result<Option<Revision>, NodeMapError> {
68 self.find_bin(index, node.into())
69 self.find_bin(index, node.into())
69 }
70 }
70
71
71 /// Find the unique Revision whose `Node` starts with a given binary prefix
72 /// Find the unique Revision whose `Node` starts with a given binary prefix
72 ///
73 ///
73 /// If no Revision matches the given prefix, `Ok(None)` is returned.
74 /// If no Revision matches the given prefix, `Ok(None)` is returned.
74 ///
75 ///
75 /// If several Revisions match the given prefix, a [`MultipleResults`]
76 /// If several Revisions match the given prefix, a [`MultipleResults`]
76 /// error is returned.
77 /// error is returned.
77 fn find_bin<'a>(
78 fn find_bin<'a>(
78 &self,
79 &self,
79 idx: &impl RevlogIndex,
80 idx: &impl RevlogIndex,
80 prefix: NodePrefixRef<'a>,
81 prefix: NodePrefixRef<'a>,
81 ) -> Result<Option<Revision>, NodeMapError>;
82 ) -> Result<Option<Revision>, NodeMapError>;
82
83
83 /// Find the unique Revision whose `Node` hexadecimal string representation
84 /// Find the unique Revision whose `Node` hexadecimal string representation
84 /// starts with a given prefix
85 /// starts with a given prefix
85 ///
86 ///
86 /// If no Revision matches the given prefix, `Ok(None)` is returned.
87 /// If no Revision matches the given prefix, `Ok(None)` is returned.
87 ///
88 ///
88 /// If several Revisions match the given prefix, a [`MultipleResults`]
89 /// If several Revisions match the given prefix, a [`MultipleResults`]
89 /// error is returned.
90 /// error is returned.
90 fn find_hex(
91 fn find_hex(
91 &self,
92 &self,
92 idx: &impl RevlogIndex,
93 idx: &impl RevlogIndex,
93 prefix: &str,
94 prefix: &str,
94 ) -> Result<Option<Revision>, NodeMapError> {
95 ) -> Result<Option<Revision>, NodeMapError> {
95 self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
96 self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
96 }
97 }
97 }
98 }
98
99
100 pub trait MutableNodeMap: NodeMap {
101 fn insert<I: RevlogIndex>(
102 &mut self,
103 index: &I,
104 node: &Node,
105 rev: Revision,
106 ) -> Result<(), NodeMapError>;
107 }
108
99 /// Low level NodeTree [`Blocks`] elements
109 /// Low level NodeTree [`Blocks`] elements
100 ///
110 ///
101 /// These are exactly as for instance on persistent storage.
111 /// These are exactly as for instance on persistent storage.
102 type RawElement = i32;
112 type RawElement = i32;
103
113
104 /// High level representation of values in NodeTree
114 /// High level representation of values in NodeTree
105 /// [`Blocks`](struct.Block.html)
115 /// [`Blocks`](struct.Block.html)
106 ///
116 ///
107 /// This is the high level representation that most algorithms should
117 /// This is the high level representation that most algorithms should
108 /// use.
118 /// use.
109 #[derive(Clone, Debug, Eq, PartialEq)]
119 #[derive(Clone, Debug, Eq, PartialEq)]
110 enum Element {
120 enum Element {
111 Rev(Revision),
121 Rev(Revision),
112 Block(usize),
122 Block(usize),
113 None,
123 None,
114 }
124 }
115
125
116 impl From<RawElement> for Element {
126 impl From<RawElement> for Element {
117 /// Conversion from low level representation, after endianness conversion.
127 /// Conversion from low level representation, after endianness conversion.
118 ///
128 ///
119 /// See [`Block`](struct.Block.html) for explanation about the encoding.
129 /// See [`Block`](struct.Block.html) for explanation about the encoding.
120 fn from(raw: RawElement) -> Element {
130 fn from(raw: RawElement) -> Element {
121 if raw >= 0 {
131 if raw >= 0 {
122 Element::Block(raw as usize)
132 Element::Block(raw as usize)
123 } else if raw == -1 {
133 } else if raw == -1 {
124 Element::None
134 Element::None
125 } else {
135 } else {
126 Element::Rev(-raw - 2)
136 Element::Rev(-raw - 2)
127 }
137 }
128 }
138 }
129 }
139 }
130
140
131 impl From<Element> for RawElement {
141 impl From<Element> for RawElement {
132 fn from(element: Element) -> RawElement {
142 fn from(element: Element) -> RawElement {
133 match element {
143 match element {
134 Element::None => 0,
144 Element::None => 0,
135 Element::Block(i) => i as RawElement,
145 Element::Block(i) => i as RawElement,
136 Element::Rev(rev) => -rev - 2,
146 Element::Rev(rev) => -rev - 2,
137 }
147 }
138 }
148 }
139 }
149 }
140
150
141 /// A logical block of the `NodeTree`, packed with a fixed size.
151 /// A logical block of the `NodeTree`, packed with a fixed size.
142 ///
152 ///
143 /// These are always used in container types implementing `Index<Block>`,
153 /// These are always used in container types implementing `Index<Block>`,
144 /// such as `&Block`
154 /// such as `&Block`
145 ///
155 ///
146 /// As an array of integers, its ith element encodes that the
156 /// As an array of integers, its ith element encodes that the
147 /// ith potential edge from the block, representing the ith hexadecimal digit
157 /// ith potential edge from the block, representing the ith hexadecimal digit
148 /// (nybble) `i` is either:
158 /// (nybble) `i` is either:
149 ///
159 ///
150 /// - absent (value -1)
160 /// - absent (value -1)
151 /// - another `Block` in the same indexable container (value β‰₯ 0)
161 /// - another `Block` in the same indexable container (value β‰₯ 0)
152 /// - a `Revision` leaf (value ≀ -2)
162 /// - a `Revision` leaf (value ≀ -2)
153 ///
163 ///
154 /// Endianness has to be fixed for consistency on shared storage across
164 /// Endianness has to be fixed for consistency on shared storage across
155 /// different architectures.
165 /// different architectures.
156 ///
166 ///
157 /// A key difference with the C `nodetree` is that we need to be
167 /// A key difference with the C `nodetree` is that we need to be
158 /// able to represent the [`Block`] at index 0, hence -1 is the empty marker
168 /// able to represent the [`Block`] at index 0, hence -1 is the empty marker
159 /// rather than 0 and the `Revision` range upper limit of -2 instead of -1.
169 /// rather than 0 and the `Revision` range upper limit of -2 instead of -1.
160 ///
170 ///
161 /// Another related difference is that `NULL_REVISION` (-1) is not
171 /// Another related difference is that `NULL_REVISION` (-1) is not
162 /// represented at all, because we want an immutable empty nodetree
172 /// represented at all, because we want an immutable empty nodetree
163 /// to be valid.
173 /// to be valid.
164
174
165 #[derive(Clone, PartialEq)]
175 #[derive(Clone, PartialEq)]
166 pub struct Block([RawElement; 16]);
176 pub struct Block([RawElement; 16]);
167
177
168 impl Block {
178 impl Block {
169 fn new() -> Self {
179 fn new() -> Self {
170 Block([-1; 16])
180 Block([-1; 16])
171 }
181 }
172
182
173 fn get(&self, nybble: u8) -> Element {
183 fn get(&self, nybble: u8) -> Element {
174 Element::from(RawElement::from_be(self.0[nybble as usize]))
184 Element::from(RawElement::from_be(self.0[nybble as usize]))
175 }
185 }
176
186
177 fn set(&mut self, nybble: u8, element: Element) {
187 fn set(&mut self, nybble: u8, element: Element) {
178 self.0[nybble as usize] = RawElement::to_be(element.into())
188 self.0[nybble as usize] = RawElement::to_be(element.into())
179 }
189 }
180 }
190 }
181
191
182 impl fmt::Debug for Block {
192 impl fmt::Debug for Block {
183 /// sparse representation for testing and debugging purposes
193 /// sparse representation for testing and debugging purposes
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 f.debug_map()
195 f.debug_map()
186 .entries((0..16).filter_map(|i| match self.get(i) {
196 .entries((0..16).filter_map(|i| match self.get(i) {
187 Element::None => None,
197 Element::None => None,
188 element => Some((i, element)),
198 element => Some((i, element)),
189 }))
199 }))
190 .finish()
200 .finish()
191 }
201 }
192 }
202 }
193
203
194 /// A mutable 16-radix tree with the root block logically at the end
204 /// A mutable 16-radix tree with the root block logically at the end
195 ///
205 ///
196 /// Because of the append only nature of our node trees, we need to
206 /// Because of the append only nature of our node trees, we need to
197 /// keep the original untouched and store new blocks separately.
207 /// keep the original untouched and store new blocks separately.
198 ///
208 ///
199 /// The mutable root `Block` is kept apart so that we don't have to rebump
209 /// The mutable root `Block` is kept apart so that we don't have to rebump
200 /// it on each insertion.
210 /// it on each insertion.
201 pub struct NodeTree {
211 pub struct NodeTree {
202 readonly: Box<dyn Deref<Target = [Block]> + Send>,
212 readonly: Box<dyn Deref<Target = [Block]> + Send>,
203 growable: Vec<Block>,
213 growable: Vec<Block>,
204 root: Block,
214 root: Block,
205 }
215 }
206
216
207 impl Index<usize> for NodeTree {
217 impl Index<usize> for NodeTree {
208 type Output = Block;
218 type Output = Block;
209
219
210 fn index(&self, i: usize) -> &Block {
220 fn index(&self, i: usize) -> &Block {
211 let ro_len = self.readonly.len();
221 let ro_len = self.readonly.len();
212 if i < ro_len {
222 if i < ro_len {
213 &self.readonly[i]
223 &self.readonly[i]
214 } else if i == ro_len + self.growable.len() {
224 } else if i == ro_len + self.growable.len() {
215 &self.root
225 &self.root
216 } else {
226 } else {
217 &self.growable[i - ro_len]
227 &self.growable[i - ro_len]
218 }
228 }
219 }
229 }
220 }
230 }
221
231
222 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
232 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
223 fn has_prefix_or_none<'p>(
233 fn has_prefix_or_none<'p>(
224 idx: &impl RevlogIndex,
234 idx: &impl RevlogIndex,
225 prefix: NodePrefixRef<'p>,
235 prefix: NodePrefixRef<'p>,
226 rev: Revision,
236 rev: Revision,
227 ) -> Result<Option<Revision>, NodeMapError> {
237 ) -> Result<Option<Revision>, NodeMapError> {
228 idx.node(rev)
238 idx.node(rev)
229 .ok_or_else(|| NodeMapError::RevisionNotInIndex(rev))
239 .ok_or_else(|| NodeMapError::RevisionNotInIndex(rev))
230 .map(|node| {
240 .map(|node| {
231 if prefix.is_prefix_of(node) {
241 if prefix.is_prefix_of(node) {
232 Some(rev)
242 Some(rev)
233 } else {
243 } else {
234 None
244 None
235 }
245 }
236 })
246 })
237 }
247 }
238
248
239 impl NodeTree {
249 impl NodeTree {
240 /// Initiate a NodeTree from an immutable slice-like of `Block`
250 /// Initiate a NodeTree from an immutable slice-like of `Block`
241 ///
251 ///
242 /// We keep `readonly` and clone its root block if it isn't empty.
252 /// We keep `readonly` and clone its root block if it isn't empty.
243 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self {
253 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self {
244 let root = readonly
254 let root = readonly
245 .last()
255 .last()
246 .map(|b| b.clone())
256 .map(|b| b.clone())
247 .unwrap_or_else(|| Block::new());
257 .unwrap_or_else(|| Block::new());
248 NodeTree {
258 NodeTree {
249 readonly: readonly,
259 readonly: readonly,
250 growable: Vec::new(),
260 growable: Vec::new(),
251 root: root,
261 root: root,
252 }
262 }
253 }
263 }
254
264
255 /// Total number of blocks
265 /// Total number of blocks
256 fn len(&self) -> usize {
266 fn len(&self) -> usize {
257 self.readonly.len() + self.growable.len() + 1
267 self.readonly.len() + self.growable.len() + 1
258 }
268 }
259
269
260 /// Implemented for completeness
270 /// Implemented for completeness
261 ///
271 ///
262 /// A `NodeTree` always has at least the mutable root block.
272 /// A `NodeTree` always has at least the mutable root block.
263 #[allow(dead_code)]
273 #[allow(dead_code)]
264 fn is_empty(&self) -> bool {
274 fn is_empty(&self) -> bool {
265 false
275 false
266 }
276 }
267
277
268 /// Main working method for `NodeTree` searches
278 /// Main working method for `NodeTree` searches
269 ///
279 ///
270 /// This partial implementation lacks special cases for NULL_REVISION
280 /// This partial implementation lacks special cases for NULL_REVISION
271 fn lookup<'p>(
281 fn lookup<'p>(
272 &self,
282 &self,
273 prefix: NodePrefixRef<'p>,
283 prefix: NodePrefixRef<'p>,
274 ) -> Result<Option<Revision>, NodeMapError> {
284 ) -> Result<Option<Revision>, NodeMapError> {
275 for visit_item in self.visit(prefix) {
285 for visit_item in self.visit(prefix) {
276 if let Some(opt) = visit_item.final_revision() {
286 if let Some(opt) = visit_item.final_revision() {
277 return Ok(opt);
287 return Ok(opt);
278 }
288 }
279 }
289 }
280 Err(NodeMapError::MultipleResults)
290 Err(NodeMapError::MultipleResults)
281 }
291 }
282
292
283 fn visit<'n, 'p>(
293 fn visit<'n, 'p>(
284 &'n self,
294 &'n self,
285 prefix: NodePrefixRef<'p>,
295 prefix: NodePrefixRef<'p>,
286 ) -> NodeTreeVisitor<'n, 'p> {
296 ) -> NodeTreeVisitor<'n, 'p> {
287 NodeTreeVisitor {
297 NodeTreeVisitor {
288 nt: self,
298 nt: self,
289 prefix: prefix,
299 prefix: prefix,
290 visit: self.len() - 1,
300 visit: self.len() - 1,
291 nybble_idx: 0,
301 nybble_idx: 0,
292 done: false,
302 done: false,
293 }
303 }
294 }
304 }
305 /// Return a mutable reference for `Block` at index `idx`.
306 ///
307 /// If `idx` lies in the immutable area, then the reference is to
308 /// a newly appended copy.
309 ///
310 /// Returns (new_idx, glen, mut_ref) where
311 ///
312 /// - `new_idx` is the index of the mutable `Block`
313 /// - `mut_ref` is a mutable reference to the mutable Block.
314 /// - `glen` is the new length of `self.growable`
315 ///
316 /// Note: the caller wouldn't be allowed to query `self.growable.len()`
317 /// itself because of the mutable borrow taken with the returned `Block`
318 fn mutable_block(&mut self, idx: usize) -> (usize, &mut Block, usize) {
319 let ro_blocks = &self.readonly;
320 let ro_len = ro_blocks.len();
321 let glen = self.growable.len();
322 if idx < ro_len {
323 // TODO OPTIM I think this makes two copies
324 self.growable.push(ro_blocks[idx].clone());
325 (glen + ro_len, &mut self.growable[glen], glen + 1)
326 } else if glen + ro_len == idx {
327 (idx, &mut self.root, glen)
328 } else {
329 (idx, &mut self.growable[idx - ro_len], glen)
330 }
331 }
332
333 /// Main insertion method
334 ///
335 /// This will dive in the node tree to find the deepest `Block` for
336 /// `node`, split it as much as needed and record `node` in there.
337 /// The method then backtracks, updating references in all the visited
338 /// blocks from the root.
339 ///
340 /// All the mutated `Block` are copied first to the growable part if
341 /// needed. That happens for those in the immutable part except the root.
342 pub fn insert<I: RevlogIndex>(
343 &mut self,
344 index: &I,
345 node: &Node,
346 rev: Revision,
347 ) -> Result<(), NodeMapError> {
348 let ro_len = &self.readonly.len();
349
350 let mut visit_steps: Vec<_> = self.visit(node.into()).collect();
351 let read_nybbles = visit_steps.len();
352 // visit_steps cannot be empty, since we always visit the root block
353 let deepest = visit_steps.pop().unwrap();
354
355 let (mut block_idx, mut block, mut glen) =
356 self.mutable_block(deepest.block_idx);
357
358 if let Element::Rev(old_rev) = deepest.element {
359 let old_node = index
360 .node(old_rev)
361 .ok_or_else(|| NodeMapError::RevisionNotInIndex(old_rev))?;
362 if old_node == node {
363 return Ok(()); // avoid creating lots of useless blocks
364 }
365
366 // Looping over the tail of nybbles in both nodes, creating
367 // new blocks until we find the difference
368 let mut new_block_idx = ro_len + glen;
369 let mut nybble = deepest.nybble;
370 for nybble_pos in read_nybbles..node.nybbles_len() {
371 block.set(nybble, Element::Block(new_block_idx));
372
373 let new_nybble = node.get_nybble(nybble_pos);
374 let old_nybble = old_node.get_nybble(nybble_pos);
375
376 if old_nybble == new_nybble {
377 self.growable.push(Block::new());
378 block = &mut self.growable[glen];
379 glen += 1;
380 new_block_idx += 1;
381 nybble = new_nybble;
382 } else {
383 let mut new_block = Block::new();
384 new_block.set(old_nybble, Element::Rev(old_rev));
385 new_block.set(new_nybble, Element::Rev(rev));
386 self.growable.push(new_block);
387 break;
388 }
389 }
390 } else {
391 // Free slot in the deepest block: no splitting has to be done
392 block.set(deepest.nybble, Element::Rev(rev));
393 }
394
395 // Backtrack over visit steps to update references
396 while let Some(visited) = visit_steps.pop() {
397 let to_write = Element::Block(block_idx);
398 if visit_steps.is_empty() {
399 self.root.set(visited.nybble, to_write);
400 break;
401 }
402 let (new_idx, block, _) = self.mutable_block(visited.block_idx);
403 if block.get(visited.nybble) == to_write {
404 break;
405 }
406 block.set(visited.nybble, to_write);
407 block_idx = new_idx;
408 }
409 Ok(())
410 }
295 }
411 }
296
412
297 struct NodeTreeVisitor<'n, 'p> {
413 struct NodeTreeVisitor<'n, 'p> {
298 nt: &'n NodeTree,
414 nt: &'n NodeTree,
299 prefix: NodePrefixRef<'p>,
415 prefix: NodePrefixRef<'p>,
300 visit: usize,
416 visit: usize,
301 nybble_idx: usize,
417 nybble_idx: usize,
302 done: bool,
418 done: bool,
303 }
419 }
304
420
305 #[derive(Debug, PartialEq, Clone)]
421 #[derive(Debug, PartialEq, Clone)]
306 struct NodeTreeVisitItem {
422 struct NodeTreeVisitItem {
307 block_idx: usize,
423 block_idx: usize,
308 nybble: u8,
424 nybble: u8,
309 element: Element,
425 element: Element,
310 }
426 }
311
427
312 impl<'n, 'p> Iterator for NodeTreeVisitor<'n, 'p> {
428 impl<'n, 'p> Iterator for NodeTreeVisitor<'n, 'p> {
313 type Item = NodeTreeVisitItem;
429 type Item = NodeTreeVisitItem;
314
430
315 fn next(&mut self) -> Option<Self::Item> {
431 fn next(&mut self) -> Option<Self::Item> {
316 if self.done || self.nybble_idx >= self.prefix.len() {
432 if self.done || self.nybble_idx >= self.prefix.len() {
317 return None;
433 return None;
318 }
434 }
319
435
320 let nybble = self.prefix.get_nybble(self.nybble_idx);
436 let nybble = self.prefix.get_nybble(self.nybble_idx);
321 self.nybble_idx += 1;
437 self.nybble_idx += 1;
322
438
323 let visit = self.visit;
439 let visit = self.visit;
324 let element = self.nt[visit].get(nybble);
440 let element = self.nt[visit].get(nybble);
325 if let Element::Block(idx) = element {
441 if let Element::Block(idx) = element {
326 self.visit = idx;
442 self.visit = idx;
327 } else {
443 } else {
328 self.done = true;
444 self.done = true;
329 }
445 }
330
446
331 Some(NodeTreeVisitItem {
447 Some(NodeTreeVisitItem {
332 block_idx: visit,
448 block_idx: visit,
333 nybble: nybble,
449 nybble: nybble,
334 element: element,
450 element: element,
335 })
451 })
336 }
452 }
337 }
453 }
338
454
339 impl NodeTreeVisitItem {
455 impl NodeTreeVisitItem {
340 // Return `Some(opt)` if this item is final, with `opt` being the
456 // Return `Some(opt)` if this item is final, with `opt` being the
341 // `Revision` that it may represent.
457 // `Revision` that it may represent.
342 //
458 //
343 // If the item is not terminal, return `None`
459 // If the item is not terminal, return `None`
344 fn final_revision(&self) -> Option<Option<Revision>> {
460 fn final_revision(&self) -> Option<Option<Revision>> {
345 match self.element {
461 match self.element {
346 Element::Block(_) => None,
462 Element::Block(_) => None,
347 Element::Rev(r) => Some(Some(r)),
463 Element::Rev(r) => Some(Some(r)),
348 Element::None => Some(None),
464 Element::None => Some(None),
349 }
465 }
350 }
466 }
351 }
467 }
352
468
353 impl From<Vec<Block>> for NodeTree {
469 impl From<Vec<Block>> for NodeTree {
354 fn from(vec: Vec<Block>) -> Self {
470 fn from(vec: Vec<Block>) -> Self {
355 Self::new(Box::new(vec))
471 Self::new(Box::new(vec))
356 }
472 }
357 }
473 }
358
474
359 impl fmt::Debug for NodeTree {
475 impl fmt::Debug for NodeTree {
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 let readonly: &[Block] = &*self.readonly;
477 let readonly: &[Block] = &*self.readonly;
362 write!(
478 write!(
363 f,
479 f,
364 "readonly: {:?}, growable: {:?}, root: {:?}",
480 "readonly: {:?}, growable: {:?}, root: {:?}",
365 readonly, self.growable, self.root
481 readonly, self.growable, self.root
366 )
482 )
367 }
483 }
368 }
484 }
369
485
486 impl Default for NodeTree {
487 /// Create a fully mutable empty NodeTree
488 fn default() -> Self {
489 NodeTree::new(Box::new(Vec::new()))
490 }
491 }
492
370 impl NodeMap for NodeTree {
493 impl NodeMap for NodeTree {
371 fn find_bin<'a>(
494 fn find_bin<'a>(
372 &self,
495 &self,
373 idx: &impl RevlogIndex,
496 idx: &impl RevlogIndex,
374 prefix: NodePrefixRef<'a>,
497 prefix: NodePrefixRef<'a>,
375 ) -> Result<Option<Revision>, NodeMapError> {
498 ) -> Result<Option<Revision>, NodeMapError> {
376 self.lookup(prefix.clone()).and_then(|opt| {
499 self.lookup(prefix.clone()).and_then(|opt| {
377 opt.map_or(Ok(None), |rev| has_prefix_or_none(idx, prefix, rev))
500 opt.map_or(Ok(None), |rev| has_prefix_or_none(idx, prefix, rev))
378 })
501 })
379 }
502 }
380 }
503 }
381
504
382 #[cfg(test)]
505 #[cfg(test)]
383 mod tests {
506 mod tests {
384 use super::NodeMapError::*;
507 use super::NodeMapError::*;
385 use super::*;
508 use super::*;
386 use crate::revlog::node::{hex_pad_right, Node};
509 use crate::revlog::node::{hex_pad_right, Node};
387 use std::collections::HashMap;
510 use std::collections::HashMap;
388
511
389 /// Creates a `Block` using a syntax close to the `Debug` output
512 /// Creates a `Block` using a syntax close to the `Debug` output
390 macro_rules! block {
513 macro_rules! block {
391 {$($nybble:tt : $variant:ident($val:tt)),*} => (
514 {$($nybble:tt : $variant:ident($val:tt)),*} => (
392 {
515 {
393 let mut block = Block::new();
516 let mut block = Block::new();
394 $(block.set($nybble, Element::$variant($val)));*;
517 $(block.set($nybble, Element::$variant($val)));*;
395 block
518 block
396 }
519 }
397 )
520 )
398 }
521 }
399
522
400 #[test]
523 #[test]
401 fn test_block_debug() {
524 fn test_block_debug() {
402 let mut block = Block::new();
525 let mut block = Block::new();
403 block.set(1, Element::Rev(3));
526 block.set(1, Element::Rev(3));
404 block.set(10, Element::Block(0));
527 block.set(10, Element::Block(0));
405 assert_eq!(format!("{:?}", block), "{1: Rev(3), 10: Block(0)}");
528 assert_eq!(format!("{:?}", block), "{1: Rev(3), 10: Block(0)}");
406 }
529 }
407
530
408 #[test]
531 #[test]
409 fn test_block_macro() {
532 fn test_block_macro() {
410 let block = block! {5: Block(2)};
533 let block = block! {5: Block(2)};
411 assert_eq!(format!("{:?}", block), "{5: Block(2)}");
534 assert_eq!(format!("{:?}", block), "{5: Block(2)}");
412
535
413 let block = block! {13: Rev(15), 5: Block(2)};
536 let block = block! {13: Rev(15), 5: Block(2)};
414 assert_eq!(format!("{:?}", block), "{5: Block(2), 13: Rev(15)}");
537 assert_eq!(format!("{:?}", block), "{5: Block(2), 13: Rev(15)}");
415 }
538 }
416
539
417 #[test]
540 #[test]
418 fn test_raw_block() {
541 fn test_raw_block() {
419 let mut raw = [-1; 16];
542 let mut raw = [-1; 16];
420 raw[0] = 0;
543 raw[0] = 0;
421 raw[1] = RawElement::to_be(15);
544 raw[1] = RawElement::to_be(15);
422 raw[2] = RawElement::to_be(-2);
545 raw[2] = RawElement::to_be(-2);
423 raw[3] = RawElement::to_be(-1);
546 raw[3] = RawElement::to_be(-1);
424 raw[4] = RawElement::to_be(-3);
547 raw[4] = RawElement::to_be(-3);
425 let block = Block(raw);
548 let block = Block(raw);
426 assert_eq!(block.get(0), Element::Block(0));
549 assert_eq!(block.get(0), Element::Block(0));
427 assert_eq!(block.get(1), Element::Block(15));
550 assert_eq!(block.get(1), Element::Block(15));
428 assert_eq!(block.get(3), Element::None);
551 assert_eq!(block.get(3), Element::None);
429 assert_eq!(block.get(2), Element::Rev(0));
552 assert_eq!(block.get(2), Element::Rev(0));
430 assert_eq!(block.get(4), Element::Rev(1));
553 assert_eq!(block.get(4), Element::Rev(1));
431 }
554 }
432
555
433 type TestIndex = HashMap<Revision, Node>;
556 type TestIndex = HashMap<Revision, Node>;
434
557
435 impl RevlogIndex for TestIndex {
558 impl RevlogIndex for TestIndex {
436 fn node(&self, rev: Revision) -> Option<&Node> {
559 fn node(&self, rev: Revision) -> Option<&Node> {
437 self.get(&rev)
560 self.get(&rev)
438 }
561 }
439
562
440 fn len(&self) -> usize {
563 fn len(&self) -> usize {
441 self.len()
564 self.len()
442 }
565 }
443 }
566 }
444
567
445 /// Pad hexadecimal Node prefix with zeros on the right, then insert
568 /// Pad hexadecimal Node prefix with zeros on the right
446 ///
569 ///
447 /// This avoids having to repeatedly write very long hexadecimal
570 /// This avoids having to repeatedly write very long hexadecimal
448 /// strings for test data, and brings actual hash size independency.
571 /// strings for test data, and brings actual hash size independency.
572 #[cfg(test)]
573 fn pad_node(hex: &str) -> Node {
574 Node::from_hex(&hex_pad_right(hex)).unwrap()
575 }
576
577 /// Pad hexadecimal Node prefix with zeros on the right, then insert
449 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
578 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
450 idx.insert(rev, Node::from_hex(&hex_pad_right(hex)).unwrap());
579 idx.insert(rev, pad_node(hex));
451 }
580 }
452
581
453 fn sample_nodetree() -> NodeTree {
582 fn sample_nodetree() -> NodeTree {
454 NodeTree::from(vec![
583 NodeTree::from(vec![
455 block![0: Rev(9)],
584 block![0: Rev(9)],
456 block![0: Rev(0), 1: Rev(9)],
585 block![0: Rev(0), 1: Rev(9)],
457 block![0: Block(1), 1:Rev(1)],
586 block![0: Block(1), 1:Rev(1)],
458 ])
587 ])
459 }
588 }
460
589
461 #[test]
590 #[test]
462 fn test_nt_debug() {
591 fn test_nt_debug() {
463 let nt = sample_nodetree();
592 let nt = sample_nodetree();
464 assert_eq!(
593 assert_eq!(
465 format!("{:?}", nt),
594 format!("{:?}", nt),
466 "readonly: \
595 "readonly: \
467 [{0: Rev(9)}, {0: Rev(0), 1: Rev(9)}, {0: Block(1), 1: Rev(1)}], \
596 [{0: Rev(9)}, {0: Rev(0), 1: Rev(9)}, {0: Block(1), 1: Rev(1)}], \
468 growable: [], \
597 growable: [], \
469 root: {0: Block(1), 1: Rev(1)}",
598 root: {0: Block(1), 1: Rev(1)}",
470 );
599 );
471 }
600 }
472
601
473 #[test]
602 #[test]
474 fn test_immutable_find_simplest() -> Result<(), NodeMapError> {
603 fn test_immutable_find_simplest() -> Result<(), NodeMapError> {
475 let mut idx: TestIndex = HashMap::new();
604 let mut idx: TestIndex = HashMap::new();
476 pad_insert(&mut idx, 1, "1234deadcafe");
605 pad_insert(&mut idx, 1, "1234deadcafe");
477
606
478 let nt = NodeTree::from(vec![block! {1: Rev(1)}]);
607 let nt = NodeTree::from(vec![block! {1: Rev(1)}]);
479 assert_eq!(nt.find_hex(&idx, "1")?, Some(1));
608 assert_eq!(nt.find_hex(&idx, "1")?, Some(1));
480 assert_eq!(nt.find_hex(&idx, "12")?, Some(1));
609 assert_eq!(nt.find_hex(&idx, "12")?, Some(1));
481 assert_eq!(nt.find_hex(&idx, "1234de")?, Some(1));
610 assert_eq!(nt.find_hex(&idx, "1234de")?, Some(1));
482 assert_eq!(nt.find_hex(&idx, "1a")?, None);
611 assert_eq!(nt.find_hex(&idx, "1a")?, None);
483 assert_eq!(nt.find_hex(&idx, "ab")?, None);
612 assert_eq!(nt.find_hex(&idx, "ab")?, None);
484
613
485 // and with full binary Nodes
614 // and with full binary Nodes
486 assert_eq!(nt.find_node(&idx, idx.get(&1).unwrap())?, Some(1));
615 assert_eq!(nt.find_node(&idx, idx.get(&1).unwrap())?, Some(1));
487 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
616 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
488 assert_eq!(nt.find_node(&idx, &unknown)?, None);
617 assert_eq!(nt.find_node(&idx, &unknown)?, None);
489 Ok(())
618 Ok(())
490 }
619 }
491
620
492 #[test]
621 #[test]
493 fn test_immutable_find_one_jump() {
622 fn test_immutable_find_one_jump() {
494 let mut idx = TestIndex::new();
623 let mut idx = TestIndex::new();
495 pad_insert(&mut idx, 9, "012");
624 pad_insert(&mut idx, 9, "012");
496 pad_insert(&mut idx, 0, "00a");
625 pad_insert(&mut idx, 0, "00a");
497
626
498 let nt = sample_nodetree();
627 let nt = sample_nodetree();
499
628
500 assert_eq!(nt.find_hex(&idx, "0"), Err(MultipleResults));
629 assert_eq!(nt.find_hex(&idx, "0"), Err(MultipleResults));
501 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
630 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
502 assert_eq!(nt.find_hex(&idx, "00"), Ok(Some(0)));
631 assert_eq!(nt.find_hex(&idx, "00"), Ok(Some(0)));
503 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
632 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
504 }
633 }
505
634
506 #[test]
635 #[test]
507 fn test_mutated_find() -> Result<(), NodeMapError> {
636 fn test_mutated_find() -> Result<(), NodeMapError> {
508 let mut idx = TestIndex::new();
637 let mut idx = TestIndex::new();
509 pad_insert(&mut idx, 9, "012");
638 pad_insert(&mut idx, 9, "012");
510 pad_insert(&mut idx, 0, "00a");
639 pad_insert(&mut idx, 0, "00a");
511 pad_insert(&mut idx, 2, "cafe");
640 pad_insert(&mut idx, 2, "cafe");
512 pad_insert(&mut idx, 3, "15");
641 pad_insert(&mut idx, 3, "15");
513 pad_insert(&mut idx, 1, "10");
642 pad_insert(&mut idx, 1, "10");
514
643
515 let nt = NodeTree {
644 let nt = NodeTree {
516 readonly: sample_nodetree().readonly,
645 readonly: sample_nodetree().readonly,
517 growable: vec![block![0: Rev(1), 5: Rev(3)]],
646 growable: vec![block![0: Rev(1), 5: Rev(3)]],
518 root: block![0: Block(1), 1:Block(3), 12: Rev(2)],
647 root: block![0: Block(1), 1:Block(3), 12: Rev(2)],
519 };
648 };
520 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
649 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
521 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
650 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
522 assert_eq!(nt.find_hex(&idx, "00")?, Some(0));
651 assert_eq!(nt.find_hex(&idx, "00")?, Some(0));
523 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
652 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
524 Ok(())
653 Ok(())
525 }
654 }
655
656 struct TestNtIndex {
657 index: TestIndex,
658 nt: NodeTree,
659 }
660
661 impl TestNtIndex {
662 fn new() -> Self {
663 TestNtIndex {
664 index: HashMap::new(),
665 nt: NodeTree::default(),
666 }
667 }
668
669 fn insert(
670 &mut self,
671 rev: Revision,
672 hex: &str,
673 ) -> Result<(), NodeMapError> {
674 let node = pad_node(hex);
675 self.index.insert(rev, node.clone());
676 self.nt.insert(&self.index, &node, rev)?;
677 Ok(())
678 }
679
680 fn find_hex(
681 &self,
682 prefix: &str,
683 ) -> Result<Option<Revision>, NodeMapError> {
684 self.nt.find_hex(&self.index, prefix)
685 }
686
687 /// Drain `added` and restart a new one
688 fn commit(self) -> Self {
689 let mut as_vec: Vec<Block> =
690 self.nt.readonly.iter().map(|block| block.clone()).collect();
691 as_vec.extend(self.nt.growable);
692 as_vec.push(self.nt.root);
693
694 Self {
695 index: self.index,
696 nt: NodeTree::from(as_vec).into(),
697 }
698 }
699 }
700
701 #[test]
702 fn test_insert_full_mutable() -> Result<(), NodeMapError> {
703 let mut idx = TestNtIndex::new();
704 idx.insert(0, "1234")?;
705 assert_eq!(idx.find_hex("1")?, Some(0));
706 assert_eq!(idx.find_hex("12")?, Some(0));
707
708 // let's trigger a simple split
709 idx.insert(1, "1a34")?;
710 assert_eq!(idx.nt.growable.len(), 1);
711 assert_eq!(idx.find_hex("12")?, Some(0));
712 assert_eq!(idx.find_hex("1a")?, Some(1));
713
714 // reinserting is a no_op
715 idx.insert(1, "1a34")?;
716 assert_eq!(idx.nt.growable.len(), 1);
717 assert_eq!(idx.find_hex("12")?, Some(0));
718 assert_eq!(idx.find_hex("1a")?, Some(1));
719
720 idx.insert(2, "1a01")?;
721 assert_eq!(idx.nt.growable.len(), 2);
722 assert_eq!(idx.find_hex("1a"), Err(NodeMapError::MultipleResults));
723 assert_eq!(idx.find_hex("12")?, Some(0));
724 assert_eq!(idx.find_hex("1a3")?, Some(1));
725 assert_eq!(idx.find_hex("1a0")?, Some(2));
726 assert_eq!(idx.find_hex("1a12")?, None);
727
728 // now let's make it split and create more than one additional block
729 idx.insert(3, "1a345")?;
730 assert_eq!(idx.nt.growable.len(), 4);
731 assert_eq!(idx.find_hex("1a340")?, Some(1));
732 assert_eq!(idx.find_hex("1a345")?, Some(3));
733 assert_eq!(idx.find_hex("1a341")?, None);
734
735 Ok(())
736 }
737
738 #[test]
739 fn test_insert_extreme_splitting() -> Result<(), NodeMapError> {
740 // check that the splitting loop is long enough
741 let mut nt_idx = TestNtIndex::new();
742 let nt = &mut nt_idx.nt;
743 let idx = &mut nt_idx.index;
744
745 let node0_hex = hex_pad_right("444444");
746 let mut node1_hex = hex_pad_right("444444").clone();
747 node1_hex.pop();
748 node1_hex.push('5');
749 let node0 = Node::from_hex(&node0_hex).unwrap();
750 let node1 = Node::from_hex(&node1_hex).unwrap();
751
752 idx.insert(0, node0.clone());
753 nt.insert(idx, &node0, 0)?;
754 idx.insert(1, node1.clone());
755 nt.insert(idx, &node1, 1)?;
756
757 assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0));
758 assert_eq!(nt.find_bin(idx, (&node1).into())?, Some(1));
759 Ok(())
760 }
761
762 #[test]
763 fn test_insert_partly_immutable() -> Result<(), NodeMapError> {
764 let mut idx = TestNtIndex::new();
765 idx.insert(0, "1234")?;
766 idx.insert(1, "1235")?;
767 idx.insert(2, "131")?;
768 idx.insert(3, "cafe")?;
769 let mut idx = idx.commit();
770 assert_eq!(idx.find_hex("1234")?, Some(0));
771 assert_eq!(idx.find_hex("1235")?, Some(1));
772 assert_eq!(idx.find_hex("131")?, Some(2));
773 assert_eq!(idx.find_hex("cafe")?, Some(3));
774
775 idx.insert(4, "123A")?;
776 assert_eq!(idx.find_hex("1234")?, Some(0));
777 assert_eq!(idx.find_hex("1235")?, Some(1));
778 assert_eq!(idx.find_hex("131")?, Some(2));
779 assert_eq!(idx.find_hex("cafe")?, Some(3));
780 assert_eq!(idx.find_hex("123A")?, Some(4));
781
782 idx.insert(5, "c0")?;
783 assert_eq!(idx.find_hex("cafe")?, Some(3));
784 assert_eq!(idx.find_hex("c0")?, Some(5));
785 assert_eq!(idx.find_hex("c1")?, None);
786 assert_eq!(idx.find_hex("1234")?, Some(0));
787
788 Ok(())
789 }
526 }
790 }
General Comments 0
You need to be logged in to leave comments. Login now