##// END OF EJS Templates
rust-nodemap: insert method...
Georges Racinet -
r44831:d2da8667 default
parent child Browse files
Show More
@@ -15,6 +15,7 b''
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;
@@ -96,6 +97,15 b' pub trait NodeMap {'
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.
@@ -292,6 +302,112 b' impl NodeTree {'
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> {
@@ -367,6 +483,13 b' impl fmt::Debug for NodeTree {'
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,
@@ -442,12 +565,18 b' mod tests {'
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 {
@@ -523,4 +652,139 b' mod tests {'
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