Mercurial > hg
changeset 51215:a7bba7df9189
rust-index: implement headrevs
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Tue, 19 Sep 2023 15:21:43 +0200 |
parents | 050098d60c30 |
children | 9f876765cbe2 |
files | rust/hg-core/src/revlog/index.rs rust/hg-cpython/src/revlog.rs |
diffstat | 2 files changed, 56 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-core/src/revlog/index.rs Sat Sep 30 16:52:40 2023 +0200 +++ b/rust/hg-core/src/revlog/index.rs Tue Sep 19 15:21:43 2023 +0200 @@ -1,3 +1,4 @@ +use std::collections::hash_map::RandomState; use std::collections::HashSet; use std::fmt::Debug; use std::ops::Deref; @@ -12,8 +13,8 @@ use crate::revlog::node::Node; use crate::revlog::{Revision, NULL_REVISION}; use crate::{ - BaseRevision, FastHashMap, Graph, GraphError, RevlogError, RevlogIndex, - UncheckedRevision, + dagops, BaseRevision, FastHashMap, Graph, GraphError, RevlogError, + RevlogIndex, UncheckedRevision, }; pub const INDEX_ENTRY_SIZE: usize = 64; @@ -259,6 +260,9 @@ offsets: RwLock<Option<Vec<usize>>>, uses_generaldelta: bool, is_inline: bool, + /// Cache of the head revisions in this index, kept in sync. Should + /// be accessed via the [`Self::head_revs`] method. + head_revs: Vec<Revision>, } impl Debug for Index { @@ -358,6 +362,7 @@ offsets: RwLock::new(Some(offsets)), uses_generaldelta, is_inline: true, + head_revs: vec![], }) } else { Err(HgError::corrupted("unexpected inline revlog length")) @@ -368,6 +373,7 @@ offsets: RwLock::new(None), uses_generaldelta, is_inline: false, + head_revs: vec![], }) } } @@ -512,6 +518,26 @@ } } + /// Return the head revisions of this index + pub fn head_revs(&mut self) -> Result<Vec<Revision>, GraphError> { + if !self.head_revs.is_empty() { + return Ok(self.head_revs.to_owned()); + } + let mut revs: HashSet<Revision, RandomState> = (0..self.len()) + .into_iter() + .map(|i| Revision(i as BaseRevision)) + .collect(); + dagops::retain_heads(self, &mut revs)?; + if self.is_empty() { + revs.insert(NULL_REVISION); + } + let mut as_vec: Vec<Revision> = + revs.into_iter().map(Into::into).collect(); + as_vec.sort_unstable(); + self.head_revs = as_vec.to_owned(); + Ok(as_vec) + } + /// Obtain the delta chain for a revision. /// /// `stop_rev` specifies a revision to stop at. If not specified, we @@ -599,6 +625,7 @@ offsets.push(new_offset) } self.bytes.added.extend(revision_data.into_v1().as_bytes()); + self.head_revs.clear(); Ok(()) } @@ -612,6 +639,7 @@ if let Some(offsets) = &mut *self.get_offsets_mut() { offsets.truncate(rev.0 as usize) } + self.head_revs.clear(); Ok(()) } @@ -620,6 +648,7 @@ // instead of offsets to determine whether we're inline since we might // clear caches. This implies re-populating the offsets on-demand. self.offsets = RwLock::new(None); + self.head_revs.clear(); } /// Unchecked version of `is_snapshot`.
--- a/rust/hg-cpython/src/revlog.rs Sat Sep 30 16:52:40 2023 +0200 +++ b/rust/hg-cpython/src/revlog.rs Tue Sep 19 15:21:43 2023 +0200 @@ -13,9 +13,9 @@ use cpython::{ buffer::{Element, PyBuffer}, exc::{IndexError, ValueError}, - ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule, - PyObject, PyResult, PySet, PyString, PyTuple, Python, PythonObject, - ToPyObject, + ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyList, + PyModule, PyObject, PyResult, PySet, PyString, PyTuple, Python, + PythonObject, ToPyObject, }; use hg::{ errors::HgError, @@ -250,7 +250,11 @@ /// get head revisions def headrevs(&self, *args, **kw) -> PyResult<PyObject> { - self.call_cindex(py, "headrevs", args, kw) + let rust_res = self.inner_headrevs(py)?; + + let c_res = self.call_cindex(py, "headrevs", args, kw)?; + assert_py_eq(py, "headrevs", &rust_res, &c_res)?; + Ok(rust_res) } /// get filtered head revisions @@ -782,6 +786,17 @@ ), }) } + + fn inner_headrevs(&self, py: Python) -> PyResult<PyObject> { + let index = &mut *self.index(py).borrow_mut(); + let as_vec: Vec<PyObject> = index + .head_revs() + .map_err(|e| graph_error(py, e))? + .iter() + .map(|r| PyRevision::from(*r).into_py_object(py).into_object()) + .collect(); + Ok(PyList::new(py, &as_vec).into_object()) + } } fn revlog_error(py: Python) -> PyErr { @@ -797,6 +812,12 @@ } } +fn graph_error(py: Python, _err: hg::GraphError) -> PyErr { + // ParentOutOfRange is currently the only alternative + // in `hg::GraphError`. The C index always raises this simple ValueError. + PyErr::new::<ValueError, _>(py, "parent out of range") +} + fn nodemap_rev_not_in_index(py: Python, rev: UncheckedRevision) -> PyErr { PyErr::new::<ValueError, _>( py,