rust: Read dirstate from disk in DirstateMap constructor
Before this changeset, Python code first creates an empty `DirstateMap` Rust
object, then immediately calls its `read` method with a byte string of the
contents of the `.hg/dirstate` file.
This makes that byte string available to the constructor of `DirstateMap`
in the hg-cpython crate. This is a first step towards enabling parts of
`DirstateMap` in the hg-core crate to borrow from this buffer without copying.
Differential Revision: https://phab.mercurial-scm.org/D10556
--- a/mercurial/dirstate.py Fri Apr 30 15:40:11 2021 +0200
+++ b/mercurial/dirstate.py Fri Apr 30 18:13:31 2021 +0200
@@ -1775,20 +1775,6 @@
def get(self, *args, **kwargs):
return self._rustmap.get(*args, **kwargs)
- @propertycache
- def _rustmap(self):
- """
- Fills the Dirstatemap when called.
- """
- use_dirstate_tree = self._ui.configbool(
- b"experimental",
- b"dirstate-tree.in-memory",
- False,
- )
- self._rustmap = rustmod.DirstateMap(use_dirstate_tree)
- self.read()
- return self._rustmap
-
@property
def copymap(self):
return self._rustmap.copymap()
@@ -1872,7 +1858,11 @@
return self._parents
- def read(self):
+ @propertycache
+ def _rustmap(self):
+ """
+ Fills the Dirstatemap when called.
+ """
# ignore HG_PENDING because identity is used only for writing
self.identity = util.filestat.frompath(
self._opener.join(self._filename)
@@ -1887,18 +1877,24 @@
except IOError as err:
if err.errno != errno.ENOENT:
raise
- return
- if not st:
- return
+ st = b''
- parse_dirstate = util.nogc(self._rustmap.read)
- parents = parse_dirstate(st)
+ use_dirstate_tree = self._ui.configbool(
+ b"experimental",
+ b"dirstate-tree.in-memory",
+ False,
+ )
+ self._rustmap, parents = rustmod.DirstateMap.new(
+ use_dirstate_tree, st
+ )
+
if parents and not self._dirtyparents:
self.setparents(*parents)
self.__contains__ = self._rustmap.__contains__
self.__getitem__ = self._rustmap.__getitem__
self.get = self._rustmap.get
+ return self._rustmap
def write(self, st, now):
parents = self.parents()
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Fri Apr 30 15:40:11 2021 +0200
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Fri Apr 30 18:13:31 2021 +0200
@@ -32,8 +32,9 @@
revlog::Node,
utils::files::normalize_case,
utils::hg_path::{HgPath, HgPathBuf},
- DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
- DirstateMapError, DirstateParents, EntryState, StateMapIter,
+ DirsMultiset, DirstateEntry, DirstateError,
+ DirstateMap as RustDirstateMap, DirstateMapError, DirstateParents,
+ EntryState, StateMapIter,
};
// TODO
@@ -51,13 +52,25 @@
py_class!(pub class DirstateMap |py| {
@shared data inner: Box<dyn DirstateMapMethods + Send>;
- def __new__(_cls, use_dirstate_tree: bool) -> PyResult<Self> {
- let inner = if use_dirstate_tree {
- Box::new(hg::dirstate_tree::dirstate_map::DirstateMap::new()) as _
+ /// Returns a `(dirstate_map, parents)` tuple
+ @staticmethod
+ def new(use_dirstate_tree: bool, on_disk: PyBytes) -> PyResult<PyObject> {
+ let dirstate_error = |_: DirstateError| {
+ PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string())
+ };
+ let bytes = on_disk.data(py);
+ let (inner, parents) = if use_dirstate_tree {
+ let mut map = hg::dirstate_tree::dirstate_map::DirstateMap::new();
+ let parents = map.read(bytes).map_err(dirstate_error)?;
+ (Box::new(map) as _, parents)
} else {
- Box::new(RustDirstateMap::default()) as _
+ let mut map = RustDirstateMap::default();
+ let parents = map.read(bytes).map_err(dirstate_error)?;
+ (Box::new(map) as _, parents)
};
- Self::create_instance(py, inner)
+ let map = Self::create_instance(py, inner)?;
+ let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
+ Ok((map, parents).to_py_object(py).into_object())
}
def clear(&self) -> PyResult<PyObject> {
@@ -271,21 +284,6 @@
.to_py_object(py))
}
- def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
- match self.inner(py).borrow_mut()
- .read(st.extract::<PyBytes>(py)?.data(py))
- {
- Ok(Some(parents)) => Ok(Some(
- dirstate_parents_to_pytuple(py, parents)
- .into_object()
- )),
- Ok(None) => Ok(Some(py.None())),
- Err(_) => Err(PyErr::new::<exc::OSError, _>(
- py,
- "Dirstate error".to_string(),
- )),
- }
- }
def write(
&self,
p1: PyObject,