Show More
@@ -590,8 +590,18 b" impl Writer<'_, '_> {" | |||||
590 | &mut self, |
|
590 | &mut self, | |
591 | nodes: dirstate_map::ChildNodesRef, |
|
591 | nodes: dirstate_map::ChildNodesRef, | |
592 | ) -> Result<ChildNodes, DirstateError> { |
|
592 | ) -> Result<ChildNodes, DirstateError> { | |
593 | // `dirstate_map::ChildNodes` is a `HashMap` with undefined iteration |
|
593 | // Reuse already-written nodes if possible | |
594 | // order. Sort to enable binary search in the written file. |
|
594 | if self.append { | |
|
595 | if let dirstate_map::ChildNodesRef::OnDisk(nodes_slice) = nodes { | |||
|
596 | let start = self.offset_of(nodes_slice); | |||
|
597 | let len = child_nodes_len_from_usize(nodes_slice.len()); | |||
|
598 | return Ok(ChildNodes { start, len }); | |||
|
599 | } | |||
|
600 | } | |||
|
601 | ||||
|
602 | // `dirstate_map::ChildNodes::InMemory` contains a `HashMap` which has | |||
|
603 | // undefined iteration order. Sort to enable binary search in the | |||
|
604 | // written file. | |||
595 | let nodes = nodes.sorted(); |
|
605 | let nodes = nodes.sorted(); | |
596 | let nodes_len = nodes.len(); |
|
606 | let nodes_len = nodes.len(); | |
597 |
|
607 | |||
@@ -664,32 +674,65 b" impl Writer<'_, '_> {" | |||||
664 | // β¦ so we can write them contiguously, after writing everything else |
|
674 | // β¦ so we can write them contiguously, after writing everything else | |
665 | // they refer to. |
|
675 | // they refer to. | |
666 | let start = self.current_offset(); |
|
676 | let start = self.current_offset(); | |
667 |
let len = |
|
677 | let len = child_nodes_len_from_usize(nodes_len); | |
668 | // Could only panic with over 4 billion nodes |
|
|||
669 | .expect("dirstate-v2 path length overflow") |
|
|||
670 | .into(); |
|
|||
671 | self.out.extend(on_disk_nodes.as_bytes()); |
|
678 | self.out.extend(on_disk_nodes.as_bytes()); | |
672 | Ok(ChildNodes { start, len }) |
|
679 | Ok(ChildNodes { start, len }) | |
673 | } |
|
680 | } | |
674 |
|
681 | |||
|
682 | /// Takes a slice of items within `on_disk` and returns its offset for the | |||
|
683 | /// start of `on_disk`. | |||
|
684 | /// | |||
|
685 | /// Panics if the given slice is not within `on_disk`. | |||
|
686 | fn offset_of<T>(&self, slice: &[T]) -> Offset | |||
|
687 | where | |||
|
688 | T: BytesCast, | |||
|
689 | { | |||
|
690 | fn address_range(slice: &[u8]) -> std::ops::RangeInclusive<usize> { | |||
|
691 | let start = slice.as_ptr() as usize; | |||
|
692 | let end = start + slice.len(); | |||
|
693 | start..=end | |||
|
694 | } | |||
|
695 | let slice_addresses = address_range(slice.as_bytes()); | |||
|
696 | let on_disk_addresses = address_range(self.dirstate_map.on_disk); | |||
|
697 | assert!(on_disk_addresses.contains(slice_addresses.start())); | |||
|
698 | assert!(on_disk_addresses.contains(slice_addresses.end())); | |||
|
699 | let offset = slice_addresses.start() - on_disk_addresses.start(); | |||
|
700 | offset_from_usize(offset) | |||
|
701 | } | |||
|
702 | ||||
675 | fn current_offset(&mut self) -> Offset { |
|
703 | fn current_offset(&mut self) -> Offset { | |
676 | let mut offset = self.out.len(); |
|
704 | let mut offset = self.out.len(); | |
677 | if self.append { |
|
705 | if self.append { | |
678 | offset += self.dirstate_map.on_disk.len() |
|
706 | offset += self.dirstate_map.on_disk.len() | |
679 | } |
|
707 | } | |
680 |
|
|
708 | offset_from_usize(offset) | |
681 | // Could only panic for a dirstate file larger than 4 GiB |
|
|||
682 | .expect("dirstate-v2 offset overflow") |
|
|||
683 | .into() |
|
|||
684 | } |
|
709 | } | |
685 |
|
710 | |||
686 | fn write_path(&mut self, slice: &[u8]) -> PathSlice { |
|
711 | fn write_path(&mut self, slice: &[u8]) -> PathSlice { | |
687 | let start = self.current_offset(); |
|
712 | let start = self.current_offset(); | |
688 |
let len = |
|
713 | let len = path_len_from_usize(slice.len()); | |
689 | // Could only panic for paths over 64 KiB |
|
|||
690 | .expect("dirstate-v2 path length overflow") |
|
|||
691 | .into(); |
|
|||
692 | self.out.extend(slice.as_bytes()); |
|
714 | self.out.extend(slice.as_bytes()); | |
693 | PathSlice { start, len } |
|
715 | PathSlice { start, len } | |
694 | } |
|
716 | } | |
695 | } |
|
717 | } | |
|
718 | ||||
|
719 | fn offset_from_usize(x: usize) -> Offset { | |||
|
720 | u32::try_from(x) | |||
|
721 | // Could only panic for a dirstate file larger than 4 GiB | |||
|
722 | .expect("dirstate-v2 offset overflow") | |||
|
723 | .into() | |||
|
724 | } | |||
|
725 | ||||
|
726 | fn child_nodes_len_from_usize(x: usize) -> Size { | |||
|
727 | u32::try_from(x) | |||
|
728 | // Could only panic with over 4 billion nodes | |||
|
729 | .expect("dirstate-v2 slice length overflow") | |||
|
730 | .into() | |||
|
731 | } | |||
|
732 | ||||
|
733 | fn path_len_from_usize(x: usize) -> PathSize { | |||
|
734 | u16::try_from(x) | |||
|
735 | // Could only panic for paths over 64 KiB | |||
|
736 | .expect("dirstate-v2 path length overflow") | |||
|
737 | .into() | |||
|
738 | } |
General Comments 0
You need to be logged in to leave comments.
Login now