| 111 | } |
| 112 | |
| 113 | fn find_block_in_inode( |
| 114 | &self, |
| 115 | inode: Inode, |
| 116 | pos: Position<NodeId>, |
| 117 | ) -> Result<Option<GraphNode<NodeId>>, Self::InodeError> { |
| 118 | let table = self.txn.open_multimap_table(INODE_GRAPH)?; |
| 119 | |
| 120 | let inode_id = inode.get(); |
| 121 | let change_id = pos.change.get(); |
| 122 | let target_pos = pos.pos.get(); |
| 123 | |
| 124 | // Fast path: most inode-local edge destinations point at the exact |
| 125 | // start of the next span. Probe that narrow key range first so large |
| 126 | // single-change files do not rescan the whole inode slice per hop. |
| 127 | let exact_start_key = encode_inode_vertex(inode_id, change_id, target_pos, 0); |
| 128 | let exact_end_key = encode_inode_vertex(inode_id, change_id, target_pos, u64::MAX); |
| 129 | let mut empty_match = None; |
| 130 | |
| 131 | for result in table.range::<&[u8; 32]>(&exact_start_key..=&exact_end_key)? { |
| 132 | let (key, _values) = result?; |
| 133 | let (_, v_change, v_start, v_end) = decode_inode_vertex(key.value()); |
| 134 | |
| 135 | if v_change != change_id || v_start != target_pos { |
| 136 | continue; |
| 137 | } |
| 138 | |
| 139 | if v_start != v_end { |
| 140 | return Ok(Some(GraphNode { |
| 141 | change: NodeId::new(v_change), |
| 142 | start: ChangePosition::new(v_start), |
| 143 | end: ChangePosition::new(v_end), |
| 144 | })); |
| 145 | } |
| 146 | |
| 147 | if empty_match.is_none() { |
| 148 | empty_match = Some(GraphNode { |
| 149 | change: NodeId::new(v_change), |
| 150 | start: ChangePosition::new(v_start), |
| 151 | end: ChangePosition::new(v_end), |
| 152 | }); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | if empty_match.is_some() { |
| 157 | return Ok(empty_match); |
| 158 | } |
| 159 | |
| 160 | let start_key = encode_inode_vertex(inode_id, change_id, 0, 0); |
| 161 | let end_key = encode_inode_vertex(inode_id, change_id, u64::MAX, u64::MAX); |
| 162 | |
| 163 | for result in table.range::<&[u8; 32]>(&start_key..=&end_key)? { |
| 164 | let (key, _values) = result?; |
| 165 | let (_, v_change, v_start, v_end) = decode_inode_vertex(key.value()); |
| 166 | |
| 167 | if v_change == change_id && v_start <= target_pos && target_pos < v_end { |
| 168 | return Ok(Some(GraphNode { |
| 169 | change: NodeId::new(v_change), |
| 170 | start: ChangePosition::new(v_start), |