comparison rust/hg-core/src/revlog/mod.rs @ 50985:363620b934aa stable

revlog: fix a bug where NULL_NODE failed to be resolved to NULL_REV The problem is that nodemap already takes care about NULL_NODE resolution (in `validate_candidate` in `nodemap.rs`), so the special handling in `rev_from_node` is unnecessary and incorrect.
author Arseniy Alekseyev <aalekseyev@janestreet.com>
date Wed, 13 Sep 2023 18:28:51 +0100
parents 124c44b5cfad
children eccf7dc7c91e
comparison
equal deleted inserted replaced
50984:2dcb6a6c7540 50985:363620b934aa
223 /// revlog 223 /// revlog
224 pub fn rev_from_node( 224 pub fn rev_from_node(
225 &self, 225 &self,
226 node: NodePrefix, 226 node: NodePrefix,
227 ) -> Result<Revision, RevlogError> { 227 ) -> Result<Revision, RevlogError> {
228 let looked_up = if let Some(nodemap) = &self.nodemap { 228 if let Some(nodemap) = &self.nodemap {
229 nodemap 229 nodemap
230 .find_bin(&self.index, node)? 230 .find_bin(&self.index, node)?
231 .ok_or(RevlogError::InvalidRevision) 231 .ok_or(RevlogError::InvalidRevision)
232 } else { 232 } else {
233 self.rev_from_node_no_persistent_nodemap(node) 233 self.rev_from_node_no_persistent_nodemap(node)
234 }; 234 }
235
236 if node.is_prefix_of(&NULL_NODE) {
237 return match looked_up {
238 Ok(_) => Err(RevlogError::AmbiguousPrefix),
239 Err(RevlogError::InvalidRevision) => Ok(NULL_REVISION),
240 res => res,
241 };
242 };
243
244 looked_up
245 } 235 }
246 236
247 /// Same as `rev_from_node`, without using a persistent nodemap 237 /// Same as `rev_from_node`, without using a persistent nodemap
248 /// 238 ///
249 /// This is used as fallback when a persistent nodemap is not present. 239 /// This is used as fallback when a persistent nodemap is not present.
255 ) -> Result<Revision, RevlogError> { 245 ) -> Result<Revision, RevlogError> {
256 // Linear scan of the revlog 246 // Linear scan of the revlog
257 // TODO: consider building a non-persistent nodemap in memory to 247 // TODO: consider building a non-persistent nodemap in memory to
258 // optimize these cases. 248 // optimize these cases.
259 let mut found_by_prefix = None; 249 let mut found_by_prefix = None;
260 for rev in (0..self.len() as Revision).rev() { 250 for rev in (-1..self.len() as Revision).rev() {
261 let index_entry = self.index.get_entry(rev).ok_or_else(|| { 251 let candidate_node = if rev == -1 {
262 HgError::corrupted( 252 NULL_NODE
263 "revlog references a revision not in the index", 253 } else {
264 ) 254 let index_entry =
265 })?; 255 self.index.get_entry(rev).ok_or_else(|| {
266 if node == *index_entry.hash() { 256 HgError::corrupted(
257 "revlog references a revision not in the index",
258 )
259 })?;
260 *index_entry.hash()
261 };
262 if node == candidate_node {
267 return Ok(rev); 263 return Ok(rev);
268 } 264 }
269 if node.is_prefix_of(index_entry.hash()) { 265 if node.is_prefix_of(&candidate_node) {
270 if found_by_prefix.is_some() { 266 if found_by_prefix.is_some() {
271 return Err(RevlogError::AmbiguousPrefix); 267 return Err(RevlogError::AmbiguousPrefix);
272 } 268 }
273 found_by_prefix = Some(rev) 269 found_by_prefix = Some(rev)
274 } 270 }