Show More
@@ -226,6 +226,36 impl<'a> NodePrefixRef<'a> { | |||||
226 | assert!(i < self.len()); |
|
226 | assert!(i < self.len()); | |
227 | get_nybble(self.buf, i) |
|
227 | get_nybble(self.buf, i) | |
228 | } |
|
228 | } | |
|
229 | ||||
|
230 | /// Return the index first nybble that's different from `node` | |||
|
231 | /// | |||
|
232 | /// If the return value is `None` that means that `self` is | |||
|
233 | /// a prefix of `node`, but the current method is a bit slower | |||
|
234 | /// than `is_prefix_of`. | |||
|
235 | /// | |||
|
236 | /// Returned index is as in `get_nybble`, i.e., starting at 0. | |||
|
237 | pub fn first_different_nybble(&self, node: &Node) -> Option<usize> { | |||
|
238 | let buf = self.buf; | |||
|
239 | let until = if self.is_odd { | |||
|
240 | buf.len() - 1 | |||
|
241 | } else { | |||
|
242 | buf.len() | |||
|
243 | }; | |||
|
244 | for i in 0..until { | |||
|
245 | if buf[i] != node.data[i] { | |||
|
246 | if buf[i] & 0xf0 == node.data[i] & 0xf0 { | |||
|
247 | return Some(2 * i + 1); | |||
|
248 | } else { | |||
|
249 | return Some(2 * i); | |||
|
250 | } | |||
|
251 | } | |||
|
252 | } | |||
|
253 | if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 { | |||
|
254 | Some(until * 2) | |||
|
255 | } else { | |||
|
256 | None | |||
|
257 | } | |||
|
258 | } | |||
229 | } |
|
259 | } | |
230 |
|
260 | |||
231 | /// A shortcut for full `Node` references |
|
261 | /// A shortcut for full `Node` references | |
@@ -362,6 +392,36 mod tests { | |||||
362 | assert_eq!(prefix.borrow().get_nybble(7), 9); |
|
392 | assert_eq!(prefix.borrow().get_nybble(7), 9); | |
363 | Ok(()) |
|
393 | Ok(()) | |
364 | } |
|
394 | } | |
|
395 | ||||
|
396 | #[test] | |||
|
397 | fn test_first_different_nybble_even_prefix() { | |||
|
398 | let prefix = NodePrefix::from_hex("12ca").unwrap(); | |||
|
399 | let prefref = prefix.borrow(); | |||
|
400 | let mut node = Node::from([0; NODE_BYTES_LENGTH]); | |||
|
401 | assert_eq!(prefref.first_different_nybble(&node), Some(0)); | |||
|
402 | node.data[0] = 0x13; | |||
|
403 | assert_eq!(prefref.first_different_nybble(&node), Some(1)); | |||
|
404 | node.data[0] = 0x12; | |||
|
405 | assert_eq!(prefref.first_different_nybble(&node), Some(2)); | |||
|
406 | node.data[1] = 0xca; | |||
|
407 | // now it is a prefix | |||
|
408 | assert_eq!(prefref.first_different_nybble(&node), None); | |||
|
409 | } | |||
|
410 | ||||
|
411 | #[test] | |||
|
412 | fn test_first_different_nybble_odd_prefix() { | |||
|
413 | let prefix = NodePrefix::from_hex("12c").unwrap(); | |||
|
414 | let prefref = prefix.borrow(); | |||
|
415 | let mut node = Node::from([0; NODE_BYTES_LENGTH]); | |||
|
416 | assert_eq!(prefref.first_different_nybble(&node), Some(0)); | |||
|
417 | node.data[0] = 0x13; | |||
|
418 | assert_eq!(prefref.first_different_nybble(&node), Some(1)); | |||
|
419 | node.data[0] = 0x12; | |||
|
420 | assert_eq!(prefref.first_different_nybble(&node), Some(2)); | |||
|
421 | node.data[1] = 0xca; | |||
|
422 | // now it is a prefix | |||
|
423 | assert_eq!(prefref.first_different_nybble(&node), None); | |||
|
424 | } | |||
365 | } |
|
425 | } | |
366 |
|
426 | |||
367 | #[cfg(test)] |
|
427 | #[cfg(test)] |
@@ -17,6 +17,7 use super::{ | |||||
17 | RevlogIndex, NULL_REVISION, |
|
17 | RevlogIndex, NULL_REVISION, | |
18 | }; |
|
18 | }; | |
19 |
|
19 | |||
|
20 | use std::cmp::max; | |||
20 | use std::fmt; |
|
21 | use std::fmt; | |
21 | use std::mem; |
|
22 | use std::mem; | |
22 | use std::ops::Deref; |
|
23 | use std::ops::Deref; | |
@@ -98,6 +99,42 pub trait NodeMap { | |||||
98 | ) -> Result<Option<Revision>, NodeMapError> { |
|
99 | ) -> Result<Option<Revision>, NodeMapError> { | |
99 | self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow()) |
|
100 | self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow()) | |
100 | } |
|
101 | } | |
|
102 | ||||
|
103 | /// Give the size of the shortest node prefix that determines | |||
|
104 | /// the revision uniquely. | |||
|
105 | /// | |||
|
106 | /// 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 | |||
|
108 | /// to find the revision uniquely. | |||
|
109 | /// | |||
|
110 | /// Returns `None` if no `Revision` could be found for the prefix. | |||
|
111 | /// | |||
|
112 | /// If several Revisions match the given prefix, a [`MultipleResults`] | |||
|
113 | /// error is returned. | |||
|
114 | fn unique_prefix_len_bin<'a>( | |||
|
115 | &self, | |||
|
116 | idx: &impl RevlogIndex, | |||
|
117 | node_prefix: NodePrefixRef<'a>, | |||
|
118 | ) -> Result<Option<usize>, NodeMapError>; | |||
|
119 | ||||
|
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)?.borrow()) | |||
|
128 | } | |||
|
129 | ||||
|
130 | /// Same as `unique_prefix_len_bin`, with a full `Node` as input | |||
|
131 | fn unique_prefix_len_node( | |||
|
132 | &self, | |||
|
133 | idx: &impl RevlogIndex, | |||
|
134 | node: &Node, | |||
|
135 | ) -> Result<Option<usize>, NodeMapError> { | |||
|
136 | self.unique_prefix_len_bin(idx, node.into()) | |||
|
137 | } | |||
101 | } |
|
138 | } | |
102 |
|
139 | |||
103 | pub trait MutableNodeMap: NodeMap { |
|
140 | pub trait MutableNodeMap: NodeMap { | |
@@ -279,20 +316,24 fn has_prefix_or_none( | |||||
279 | fn validate_candidate( |
|
316 | fn validate_candidate( | |
280 | idx: &impl RevlogIndex, |
|
317 | idx: &impl RevlogIndex, | |
281 | prefix: NodePrefixRef, |
|
318 | prefix: NodePrefixRef, | |
282 |
|
|
319 | candidate: (Option<Revision>, usize), | |
283 | ) -> Result<Option<Revision>, NodeMapError> { |
|
320 | ) -> Result<(Option<Revision>, usize), NodeMapError> { | |
284 | if prefix.is_prefix_of(&NULL_NODE) { |
|
321 | let (rev, steps) = candidate; | |
285 | // NULL_REVISION always matches a prefix made only of zeros |
|
322 | if let Some(nz_nybble) = prefix.first_different_nybble(&NULL_NODE) { | |
|
323 | rev.map_or(Ok((None, steps)), |r| { | |||
|
324 | has_prefix_or_none(idx, prefix, r) | |||
|
325 | .map(|opt| (opt, max(steps, nz_nybble + 1))) | |||
|
326 | }) | |||
|
327 | } else { | |||
|
328 | // the prefix is only made of zeros; NULL_REVISION always matches it | |||
286 | // and any other *valid* result is an ambiguity |
|
329 | // and any other *valid* result is an ambiguity | |
287 | match rev { |
|
330 | match rev { | |
288 | None => Ok(Some(NULL_REVISION)), |
|
331 | None => Ok((Some(NULL_REVISION), steps + 1)), | |
289 | Some(r) => match has_prefix_or_none(idx, prefix, r)? { |
|
332 | Some(r) => match has_prefix_or_none(idx, prefix, r)? { | |
290 | None => Ok(Some(NULL_REVISION)), |
|
333 | None => Ok((Some(NULL_REVISION), steps + 1)), | |
291 | _ => Err(NodeMapError::MultipleResults), |
|
334 | _ => Err(NodeMapError::MultipleResults), | |
292 | }, |
|
335 | }, | |
293 | } |
|
336 | } | |
294 | } else { |
|
|||
295 | rev.map_or(Ok(None), |r| has_prefix_or_none(idx, prefix, r)) |
|
|||
296 | } |
|
337 | } | |
297 | } |
|
338 | } | |
298 |
|
339 | |||
@@ -387,13 +428,26 impl NodeTree { | |||||
387 | } |
|
428 | } | |
388 |
|
429 | |||
389 | /// Main working method for `NodeTree` searches |
|
430 | /// Main working method for `NodeTree` searches | |
390 | fn lookup<'p>( |
|
431 | /// | |
|
432 | /// The first returned value is the result of analysing `NodeTree` data | |||
|
433 | /// *alone*: whereas `None` guarantees that the given prefix is absent | |||
|
434 | /// from the `NodeTree` data (but still could match `NULL_NODE`), with | |||
|
435 | /// `Some(rev)`, it is to be understood that `rev` is the unique `Revision` | |||
|
436 | /// that could match the prefix. Actually, all that can be inferred from | |||
|
437 | /// the `NodeTree` data is that `rev` is the revision with the longest | |||
|
438 | /// common node prefix with the given prefix. | |||
|
439 | /// | |||
|
440 | /// The second returned value is the size of the smallest subprefix | |||
|
441 | /// of `prefix` that would give the same result, i.e. not the | |||
|
442 | /// `MultipleResults` error variant (again, using only the data of the | |||
|
443 | /// `NodeTree`). | |||
|
444 | fn lookup( | |||
391 | &self, |
|
445 | &self, | |
392 |
prefix: NodePrefixRef |
|
446 | prefix: NodePrefixRef, | |
393 | ) -> Result<Option<Revision>, NodeMapError> { |
|
447 | ) -> Result<(Option<Revision>, usize), NodeMapError> { | |
394 | for visit_item in self.visit(prefix) { |
|
448 | for (i, visit_item) in self.visit(prefix).enumerate() { | |
395 | if let Some(opt) = visit_item.final_revision() { |
|
449 | if let Some(opt) = visit_item.final_revision() { | |
396 | return Ok(opt); |
|
450 | return Ok((opt, i + 1)); | |
397 | } |
|
451 | } | |
398 | } |
|
452 | } | |
399 | Err(NodeMapError::MultipleResults) |
|
453 | Err(NodeMapError::MultipleResults) | |
@@ -638,6 +692,16 impl NodeMap for NodeTree { | |||||
638 | prefix: NodePrefixRef<'a>, |
|
692 | prefix: NodePrefixRef<'a>, | |
639 | ) -> Result<Option<Revision>, NodeMapError> { |
|
693 | ) -> Result<Option<Revision>, NodeMapError> { | |
640 | validate_candidate(idx, prefix.clone(), self.lookup(prefix)?) |
|
694 | validate_candidate(idx, prefix.clone(), self.lookup(prefix)?) | |
|
695 | .map(|(opt, _shortest)| opt) | |||
|
696 | } | |||
|
697 | ||||
|
698 | fn unique_prefix_len_bin<'a>( | |||
|
699 | &self, | |||
|
700 | idx: &impl RevlogIndex, | |||
|
701 | prefix: NodePrefixRef<'a>, | |||
|
702 | ) -> Result<Option<usize>, NodeMapError> { | |||
|
703 | validate_candidate(idx, prefix.clone(), self.lookup(prefix)?) | |||
|
704 | .map(|(opt, shortest)| opt.map(|_rev| shortest)) | |||
641 | } |
|
705 | } | |
642 | } |
|
706 | } | |
643 |
|
707 | |||
@@ -772,6 +836,7 mod tests { | |||||
772 | assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9))); |
|
836 | assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9))); | |
773 | assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults)); |
|
837 | assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults)); | |
774 | assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0))); |
|
838 | assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0))); | |
|
839 | assert_eq!(nt.unique_prefix_len_hex(&idx, "00a"), Ok(Some(3))); | |||
775 | assert_eq!(nt.find_hex(&idx, "000"), Ok(Some(NULL_REVISION))); |
|
840 | assert_eq!(nt.find_hex(&idx, "000"), Ok(Some(NULL_REVISION))); | |
776 | } |
|
841 | } | |
777 |
|
842 | |||
@@ -791,8 +856,10 mod tests { | |||||
791 | }; |
|
856 | }; | |
792 | assert_eq!(nt.find_hex(&idx, "10")?, Some(1)); |
|
857 | assert_eq!(nt.find_hex(&idx, "10")?, Some(1)); | |
793 | assert_eq!(nt.find_hex(&idx, "c")?, Some(2)); |
|
858 | assert_eq!(nt.find_hex(&idx, "c")?, Some(2)); | |
|
859 | assert_eq!(nt.unique_prefix_len_hex(&idx, "c")?, Some(1)); | |||
794 | assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults)); |
|
860 | assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults)); | |
795 | assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION)); |
|
861 | assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION)); | |
|
862 | assert_eq!(nt.unique_prefix_len_hex(&idx, "000")?, Some(3)); | |||
796 | assert_eq!(nt.find_hex(&idx, "01")?, Some(9)); |
|
863 | assert_eq!(nt.find_hex(&idx, "01")?, Some(9)); | |
797 | Ok(()) |
|
864 | Ok(()) | |
798 | } |
|
865 | } | |
@@ -828,6 +895,13 mod tests { | |||||
828 | self.nt.find_hex(&self.index, prefix) |
|
895 | self.nt.find_hex(&self.index, prefix) | |
829 | } |
|
896 | } | |
830 |
|
897 | |||
|
898 | fn unique_prefix_len_hex( | |||
|
899 | &self, | |||
|
900 | prefix: &str, | |||
|
901 | ) -> Result<Option<usize>, NodeMapError> { | |||
|
902 | self.nt.unique_prefix_len_hex(&self.index, prefix) | |||
|
903 | } | |||
|
904 | ||||
831 | /// Drain `added` and restart a new one |
|
905 | /// Drain `added` and restart a new one | |
832 | fn commit(self) -> Self { |
|
906 | fn commit(self) -> Self { | |
833 | let mut as_vec: Vec<Block> = |
|
907 | let mut as_vec: Vec<Block> = | |
@@ -880,6 +954,28 mod tests { | |||||
880 | } |
|
954 | } | |
881 |
|
955 | |||
882 | #[test] |
|
956 | #[test] | |
|
957 | fn test_unique_prefix_len_zero_prefix() { | |||
|
958 | let mut idx = TestNtIndex::new(); | |||
|
959 | idx.insert(0, "00000abcd").unwrap(); | |||
|
960 | ||||
|
961 | assert_eq!(idx.find_hex("000"), Err(NodeMapError::MultipleResults)); | |||
|
962 | // in the nodetree proper, this will be found at the first nybble | |||
|
963 | // yet the correct answer for unique_prefix_len is not 1, nor 1+1, | |||
|
964 | // but the first difference with `NULL_NODE` | |||
|
965 | assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6))); | |||
|
966 | assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6))); | |||
|
967 | ||||
|
968 | // same with odd result | |||
|
969 | idx.insert(1, "00123").unwrap(); | |||
|
970 | assert_eq!(idx.unique_prefix_len_hex("001"), Ok(Some(3))); | |||
|
971 | assert_eq!(idx.unique_prefix_len_hex("0012"), Ok(Some(3))); | |||
|
972 | ||||
|
973 | // these are unchanged of course | |||
|
974 | assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6))); | |||
|
975 | assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6))); | |||
|
976 | } | |||
|
977 | ||||
|
978 | #[test] | |||
883 | fn test_insert_extreme_splitting() -> Result<(), NodeMapError> { |
|
979 | fn test_insert_extreme_splitting() -> Result<(), NodeMapError> { | |
884 | // check that the splitting loop is long enough |
|
980 | // check that the splitting loop is long enough | |
885 | let mut nt_idx = TestNtIndex::new(); |
|
981 | let mut nt_idx = TestNtIndex::new(); |
General Comments 0
You need to be logged in to leave comments.
Login now